mobx-keystone
Advanced tools
Comparing version 1.7.0 to 1.7.1
# Change Log | ||
## 1.7.1 | ||
- Performance improvements when using the "new" non-experimental standard decorators: do not use class proxies. | ||
## 1.7.0 | ||
@@ -4,0 +8,0 @@ |
{ | ||
"name": "mobx-keystone", | ||
"version": "1.7.0", | ||
"version": "1.7.1", | ||
"description": "A MobX powered state management solution based on data trees with first class support for TypeScript, snapshots, patches and much more", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -0,0 +0,0 @@ import { failure } from "../utils" |
@@ -0,0 +0,0 @@ import type { O } from "ts-toolbelt" |
@@ -0,0 +0,0 @@ import { checkDecoratorContext } from "../utils/decorators" |
@@ -0,0 +0,0 @@ import { computed, IComputedValue } from "mobx" |
@@ -33,10 +33,11 @@ import { HookAction } from "../action/hookActions" | ||
*/ | ||
export const model: ( | ||
name: string | ||
) => <MC extends ModelClass<AnyModel | AnyDataModel>>(clazz: MC, ...args: any[]) => MC = | ||
(name) => (clazz) => { | ||
return internalModel(name, clazz) | ||
export const model = | ||
(name: string) => | ||
<MC extends ModelClass<AnyModel | AnyDataModel>>(clazz: MC, ...args: any[]): MC => { | ||
const ctx = typeof args[1] === "object" ? (args[1] as ClassDecoratorContext) : undefined | ||
return internalModel(name, clazz, ctx?.addInitializer) as any | ||
} | ||
const proxyClassHandlerTag = new WeakMap< | ||
const afterClassInitializationData = new WeakMap< | ||
ModelClass<AnyModel | AnyDataModel>, | ||
@@ -49,47 +50,54 @@ { | ||
const proxyClassHandler: ProxyHandler<ModelClass<AnyModel | AnyDataModel>> = { | ||
construct(target, args) { | ||
const instance = new (target as any)(...args) | ||
const runAfterClassInitialization = ( | ||
target: ModelClass<AnyModel | AnyDataModel>, | ||
instance: any | ||
) => { | ||
runLateInitializationFunctions(instance, runAfterNewSymbol) | ||
runLateInitializationFunctions(instance, runAfterNewSymbol) | ||
// compatibility with mobx 6 | ||
const tag = afterClassInitializationData.get(target)! | ||
if (!tag.makeObservableFailed && getMobxVersion() >= 6) { | ||
try { | ||
mobx6.makeObservable(instance) | ||
} catch (e) { | ||
// sadly we need to use this hack since the PR to do this the proper way | ||
// was rejected on the mobx side | ||
tag.makeObservableFailed = true | ||
// compatibility with mobx 6 | ||
const tag = proxyClassHandlerTag.get(target)! | ||
if (!tag.makeObservableFailed && getMobxVersion() >= 6) { | ||
try { | ||
mobx6.makeObservable(instance) | ||
} catch (e) { | ||
// sadly we need to use this hack since the PR to do this the proper way | ||
// was rejected on the mobx side | ||
tag.makeObservableFailed = true | ||
const err = e as Error | ||
if ( | ||
err.message !== | ||
"[MobX] No annotations were passed to makeObservable, but no decorator members have been found either" && | ||
err.message !== | ||
"[MobX] No annotations were passed to makeObservable, but no decorated members have been found either" | ||
) { | ||
throw err | ||
} | ||
const err = e as Error | ||
if ( | ||
err.message !== | ||
"[MobX] No annotations were passed to makeObservable, but no decorator members have been found either" && | ||
err.message !== | ||
"[MobX] No annotations were passed to makeObservable, but no decorated members have been found either" | ||
) { | ||
throw err | ||
} | ||
} | ||
} | ||
// the object is ready | ||
addHiddenProp(instance, modelInitializedSymbol, true, false) | ||
// the object is ready | ||
addHiddenProp(instance, modelInitializedSymbol, true, false) | ||
runLateInitializationFunctions(instance, runBeforeOnInitSymbol) | ||
runLateInitializationFunctions(instance, runBeforeOnInitSymbol) | ||
if (tag.type === "class" && instance.onInit) { | ||
wrapModelMethodInActionIfNeeded(instance, "onInit", HookAction.OnInit) | ||
if (tag.type === "class" && instance.onInit) { | ||
wrapModelMethodInActionIfNeeded(instance, "onInit", HookAction.OnInit) | ||
instance.onInit() | ||
} | ||
instance.onInit() | ||
} | ||
if (tag.type === "data" && instance.onLazyInit) { | ||
wrapModelMethodInActionIfNeeded(instance, "onLazyInit", HookAction.OnLazyInit) | ||
if (tag.type === "data" && instance.onLazyInit) { | ||
wrapModelMethodInActionIfNeeded(instance, "onLazyInit", HookAction.OnLazyInit) | ||
instance.onLazyInit() | ||
} | ||
instance.onLazyInit() | ||
} | ||
} | ||
const proxyClassHandler: ProxyHandler<ModelClass<AnyModel | AnyDataModel>> = { | ||
construct(clazz, args) { | ||
const instance = new (clazz as any)(...args) | ||
runAfterClassInitialization(clazz, instance) | ||
return instance | ||
@@ -101,4 +109,5 @@ }, | ||
name: string, | ||
clazz: MC | ||
): MC => { | ||
clazz: MC, | ||
addInitializer: ((initializer: (this: any) => void) => void) | undefined | ||
): MC | void => { | ||
const type = isModelClass(clazz) ? "class" : isDataModelClass(clazz) ? "data" : undefined | ||
@@ -123,8 +132,2 @@ if (!type) { | ||
// track if we fail so we only try it once per class | ||
proxyClassHandlerTag.set(clazz, { makeObservableFailed: false, type }) | ||
// trick so plain new works | ||
const proxyClass = new Proxy<MC>(clazz, proxyClassHandler) | ||
clazz.toString = () => `class ${clazz.name}#${name}` | ||
@@ -135,19 +138,47 @@ if (type === "class") { | ||
// set or else it points to the undecorated class | ||
proxyClass.prototype.constructor = proxyClass | ||
;(proxyClass as any)[modelUnwrappedClassSymbol] = clazz | ||
// track if we fail so we only try it once per class | ||
afterClassInitializationData.set(clazz, { makeObservableFailed: false, type }) | ||
const modelInfo = { | ||
name, | ||
class: proxyClass, | ||
} | ||
if (addInitializer) { | ||
// standard decorator API, avoid proxies | ||
addInitializer(function (this: any) { | ||
runAfterClassInitialization(clazz, this) | ||
}) | ||
modelInfoByName[name] = modelInfo | ||
const modelInfo = { | ||
name, | ||
class: clazz, | ||
} | ||
modelInfoByClass.set(proxyClass, modelInfo) | ||
modelInfoByClass.set(clazz, modelInfo) | ||
modelInfoByName[name] = modelInfo | ||
runLateInitializationFunctions(clazz, runAfterModelDecoratorSymbol) | ||
modelInfoByClass.set(clazz, modelInfo) | ||
return proxyClass | ||
runLateInitializationFunctions(clazz, runAfterModelDecoratorSymbol) | ||
return undefined // use same class | ||
} else { | ||
// non-standard decorator API, use proxies | ||
// trick so plain new works | ||
const proxyClass = new Proxy<MC>(clazz, proxyClassHandler) | ||
// set or else it points to the undecorated class | ||
proxyClass.prototype.constructor = proxyClass | ||
;(proxyClass as any)[modelUnwrappedClassSymbol] = clazz | ||
const modelInfo = { | ||
name, | ||
class: proxyClass, | ||
} | ||
modelInfoByName[name] = modelInfo | ||
modelInfoByClass.set(proxyClass, modelInfo) | ||
modelInfoByClass.set(clazz, modelInfo) | ||
runLateInitializationFunctions(clazz, runAfterModelDecoratorSymbol) | ||
return proxyClass | ||
} | ||
} | ||
@@ -154,0 +185,0 @@ |
@@ -0,0 +0,0 @@ import * as mobx from "mobx" |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
4294536
56876