refactor(reactivity): improve tree-shaking annotations

This commit is contained in:
Evan You 2021-06-30 11:39:31 -04:00
parent 601a290caa
commit f8a6b57ddd
2 changed files with 140 additions and 119 deletions

View File

@ -42,37 +42,42 @@ const shallowGet = /*#__PURE__*/ createGetter(false, true)
const readonlyGet = /*#__PURE__*/ createGetter(true) const readonlyGet = /*#__PURE__*/ createGetter(true)
const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true) const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true)
const arrayInstrumentations: Record<string, Function> = {} const arrayInstrumentations = /*#__PURE__*/ createArrayInstrumentations()
// instrument identity-sensitive Array methods to account for possible reactive
// values function createArrayInstrumentations() {
;(['includes', 'indexOf', 'lastIndexOf'] as const).forEach(key => { const instrumentations: Record<string, Function> = {}
const method = Array.prototype[key] as any // instrument identity-sensitive Array methods to account for possible reactive
arrayInstrumentations[key] = function(this: unknown[], ...args: unknown[]) { // values
const arr = toRaw(this) ;(['includes', 'indexOf', 'lastIndexOf'] as const).forEach(key => {
for (let i = 0, l = this.length; i < l; i++) { const method = Array.prototype[key] as any
track(arr, TrackOpTypes.GET, i + '') instrumentations[key] = function(this: unknown[], ...args: unknown[]) {
const arr = toRaw(this)
for (let i = 0, l = this.length; i < l; i++) {
track(arr, TrackOpTypes.GET, i + '')
}
// we run the method using the original args first (which may be reactive)
const res = method.apply(arr, args)
if (res === -1 || res === false) {
// if that didn't work, run it again using raw values.
return method.apply(arr, args.map(toRaw))
} else {
return res
}
} }
// we run the method using the original args first (which may be reactive) })
const res = method.apply(arr, args) // instrument length-altering mutation methods to avoid length being tracked
if (res === -1 || res === false) { // which leads to infinite loops in some cases (#2137)
// if that didn't work, run it again using raw values. ;(['push', 'pop', 'shift', 'unshift', 'splice'] as const).forEach(key => {
return method.apply(arr, args.map(toRaw)) const method = Array.prototype[key] as any
} else { instrumentations[key] = function(this: unknown[], ...args: unknown[]) {
pauseTracking()
const res = method.apply(this, args)
resetTracking()
return res return res
} }
} })
}) return instrumentations
// instrument length-altering mutation methods to avoid length being tracked }
// which leads to infinite loops in some cases (#2137)
;(['push', 'pop', 'shift', 'unshift', 'splice'] as const).forEach(key => {
const method = Array.prototype[key] as any
arrayInstrumentations[key] = function(this: unknown[], ...args: unknown[]) {
pauseTracking()
const res = method.apply(this, args)
resetTracking()
return res
}
})
function createGetter(isReadonly = false, shallow = false) { function createGetter(isReadonly = false, shallow = false) {
return function get(target: Target, key: string | symbol, receiver: object) { return function get(target: Target, key: string | symbol, receiver: object) {
@ -224,7 +229,7 @@ export const readonlyHandlers: ProxyHandler<object> = {
} }
} }
export const shallowReactiveHandlers: ProxyHandler<object> = extend( export const shallowReactiveHandlers = /*#__PURE__*/ extend(
{}, {},
mutableHandlers, mutableHandlers,
{ {
@ -236,7 +241,7 @@ export const shallowReactiveHandlers: ProxyHandler<object> = extend(
// Props handlers are special in the sense that it should not unwrap top-level // Props handlers are special in the sense that it should not unwrap top-level
// refs (in order to allow refs to be explicitly passed down), but should // refs (in order to allow refs to be explicitly passed down), but should
// retain the reactivity of the normal readonly object. // retain the reactivity of the normal readonly object.
export const shallowReadonlyHandlers: ProxyHandler<object> = extend( export const shallowReadonlyHandlers = /*#__PURE__*/ extend(
{}, {},
readonlyHandlers, readonlyHandlers,
{ {

View File

@ -236,93 +236,109 @@ function createReadonlyMethod(type: TriggerOpTypes): Function {
} }
} }
const mutableInstrumentations: Record<string, Function> = { function createInstrumentations() {
get(this: MapTypes, key: unknown) { const mutableInstrumentations: Record<string, Function> = {
return get(this, key) get(this: MapTypes, key: unknown) {
}, return get(this, key)
get size() { },
return size((this as unknown) as IterableCollections) get size() {
}, return size((this as unknown) as IterableCollections)
has, },
add, has,
set, add,
delete: deleteEntry, set,
clear, delete: deleteEntry,
forEach: createForEach(false, false) clear,
forEach: createForEach(false, false)
}
const shallowInstrumentations: Record<string, Function> = {
get(this: MapTypes, key: unknown) {
return get(this, key, false, true)
},
get size() {
return size((this as unknown) as IterableCollections)
},
has,
add,
set,
delete: deleteEntry,
clear,
forEach: createForEach(false, true)
}
const readonlyInstrumentations: Record<string, Function> = {
get(this: MapTypes, key: unknown) {
return get(this, key, true)
},
get size() {
return size((this as unknown) as IterableCollections, true)
},
has(this: MapTypes, key: unknown) {
return has.call(this, key, true)
},
add: createReadonlyMethod(TriggerOpTypes.ADD),
set: createReadonlyMethod(TriggerOpTypes.SET),
delete: createReadonlyMethod(TriggerOpTypes.DELETE),
clear: createReadonlyMethod(TriggerOpTypes.CLEAR),
forEach: createForEach(true, false)
}
const shallowReadonlyInstrumentations: Record<string, Function> = {
get(this: MapTypes, key: unknown) {
return get(this, key, true, true)
},
get size() {
return size((this as unknown) as IterableCollections, true)
},
has(this: MapTypes, key: unknown) {
return has.call(this, key, true)
},
add: createReadonlyMethod(TriggerOpTypes.ADD),
set: createReadonlyMethod(TriggerOpTypes.SET),
delete: createReadonlyMethod(TriggerOpTypes.DELETE),
clear: createReadonlyMethod(TriggerOpTypes.CLEAR),
forEach: createForEach(true, true)
}
const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]
iteratorMethods.forEach(method => {
mutableInstrumentations[method as string] = createIterableMethod(
method,
false,
false
)
readonlyInstrumentations[method as string] = createIterableMethod(
method,
true,
false
)
shallowInstrumentations[method as string] = createIterableMethod(
method,
false,
true
)
shallowReadonlyInstrumentations[method as string] = createIterableMethod(
method,
true,
true
)
})
return [
mutableInstrumentations,
readonlyInstrumentations,
shallowInstrumentations,
shallowReadonlyInstrumentations
]
} }
const shallowInstrumentations: Record<string, Function> = { const [
get(this: MapTypes, key: unknown) { mutableInstrumentations,
return get(this, key, false, true) readonlyInstrumentations,
}, shallowInstrumentations,
get size() { shallowReadonlyInstrumentations
return size((this as unknown) as IterableCollections) ] = /* #__PURE__*/ createInstrumentations()
},
has,
add,
set,
delete: deleteEntry,
clear,
forEach: createForEach(false, true)
}
const readonlyInstrumentations: Record<string, Function> = {
get(this: MapTypes, key: unknown) {
return get(this, key, true)
},
get size() {
return size((this as unknown) as IterableCollections, true)
},
has(this: MapTypes, key: unknown) {
return has.call(this, key, true)
},
add: createReadonlyMethod(TriggerOpTypes.ADD),
set: createReadonlyMethod(TriggerOpTypes.SET),
delete: createReadonlyMethod(TriggerOpTypes.DELETE),
clear: createReadonlyMethod(TriggerOpTypes.CLEAR),
forEach: createForEach(true, false)
}
const shallowReadonlyInstrumentations: Record<string, Function> = {
get(this: MapTypes, key: unknown) {
return get(this, key, true, true)
},
get size() {
return size((this as unknown) as IterableCollections, true)
},
has(this: MapTypes, key: unknown) {
return has.call(this, key, true)
},
add: createReadonlyMethod(TriggerOpTypes.ADD),
set: createReadonlyMethod(TriggerOpTypes.SET),
delete: createReadonlyMethod(TriggerOpTypes.DELETE),
clear: createReadonlyMethod(TriggerOpTypes.CLEAR),
forEach: createForEach(true, true)
}
const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]
iteratorMethods.forEach(method => {
mutableInstrumentations[method as string] = createIterableMethod(
method,
false,
false
)
readonlyInstrumentations[method as string] = createIterableMethod(
method,
true,
false
)
shallowInstrumentations[method as string] = createIterableMethod(
method,
false,
true
)
shallowReadonlyInstrumentations[method as string] = createIterableMethod(
method,
true,
true
)
})
function createInstrumentationGetter(isReadonly: boolean, shallow: boolean) { function createInstrumentationGetter(isReadonly: boolean, shallow: boolean) {
const instrumentations = shallow const instrumentations = shallow
@ -357,21 +373,21 @@ function createInstrumentationGetter(isReadonly: boolean, shallow: boolean) {
} }
export const mutableCollectionHandlers: ProxyHandler<CollectionTypes> = { export const mutableCollectionHandlers: ProxyHandler<CollectionTypes> = {
get: createInstrumentationGetter(false, false) get: /*#__PURE__*/ createInstrumentationGetter(false, false)
} }
export const shallowCollectionHandlers: ProxyHandler<CollectionTypes> = { export const shallowCollectionHandlers: ProxyHandler<CollectionTypes> = {
get: createInstrumentationGetter(false, true) get: /*#__PURE__*/ createInstrumentationGetter(false, true)
} }
export const readonlyCollectionHandlers: ProxyHandler<CollectionTypes> = { export const readonlyCollectionHandlers: ProxyHandler<CollectionTypes> = {
get: createInstrumentationGetter(true, false) get: /*#__PURE__*/ createInstrumentationGetter(true, false)
} }
export const shallowReadonlyCollectionHandlers: ProxyHandler< export const shallowReadonlyCollectionHandlers: ProxyHandler<
CollectionTypes CollectionTypes
> = { > = {
get: createInstrumentationGetter(true, true) get: /*#__PURE__*/ createInstrumentationGetter(true, true)
} }
function checkIdentityKeys( function checkIdentityKeys(