mirror of https://github.com/vuejs/core.git
fix(compat): fix $options mutation + adjust private API initialization
close #10626 close #10636
This commit is contained in:
parent
04af9504a7
commit
d58d133b1c
|
@ -15,6 +15,7 @@ import {
|
|||
DeprecationTypes,
|
||||
assertCompatEnabled,
|
||||
isCompatEnabled,
|
||||
warnDeprecation,
|
||||
} from './compatConfig'
|
||||
import { off, on, once } from './instanceEventEmitter'
|
||||
import { getCompatListeners } from './instanceListeners'
|
||||
|
@ -121,50 +122,77 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) {
|
|||
|
||||
$children: getCompatChildren,
|
||||
$listeners: getCompatListeners,
|
||||
|
||||
// inject additional properties into $options for compat
|
||||
// e.g. vuex needs this.$options.parent
|
||||
$options: i => {
|
||||
if (!isCompatEnabled(DeprecationTypes.PRIVATE_APIS, i)) {
|
||||
return resolveMergedOptions(i)
|
||||
}
|
||||
if (i.resolvedOptions) {
|
||||
return i.resolvedOptions
|
||||
}
|
||||
const res = (i.resolvedOptions = extend({}, resolveMergedOptions(i)))
|
||||
Object.defineProperties(res, {
|
||||
parent: {
|
||||
get() {
|
||||
warnDeprecation(DeprecationTypes.PRIVATE_APIS, i, '$options.parent')
|
||||
return i.proxy!.$parent
|
||||
},
|
||||
},
|
||||
propsData: {
|
||||
get() {
|
||||
warnDeprecation(
|
||||
DeprecationTypes.PRIVATE_APIS,
|
||||
i,
|
||||
'$options.propsData',
|
||||
)
|
||||
return i.vnode.props
|
||||
},
|
||||
},
|
||||
})
|
||||
return res
|
||||
},
|
||||
} as PublicPropertiesMap)
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (isCompatEnabled(DeprecationTypes.PRIVATE_APIS, null)) {
|
||||
extend(map, {
|
||||
// needed by many libs / render fns
|
||||
$vnode: i => i.vnode,
|
||||
const privateAPIs = {
|
||||
// needed by many libs / render fns
|
||||
$vnode: i => i.vnode,
|
||||
|
||||
// inject additional properties into $options for compat
|
||||
// e.g. vuex needs this.$options.parent
|
||||
$options: i => {
|
||||
const res = extend({}, resolveMergedOptions(i))
|
||||
res.parent = i.proxy!.$parent
|
||||
res.propsData = i.vnode.props
|
||||
return res
|
||||
},
|
||||
// some private properties that are likely accessed...
|
||||
_self: i => i.proxy,
|
||||
_uid: i => i.uid,
|
||||
_data: i => i.data,
|
||||
_isMounted: i => i.isMounted,
|
||||
_isDestroyed: i => i.isUnmounted,
|
||||
|
||||
// some private properties that are likely accessed...
|
||||
_self: i => i.proxy,
|
||||
_uid: i => i.uid,
|
||||
_data: i => i.data,
|
||||
_isMounted: i => i.isMounted,
|
||||
_isDestroyed: i => i.isUnmounted,
|
||||
// v2 render helpers
|
||||
$createElement: () => compatH,
|
||||
_c: () => compatH,
|
||||
_o: () => legacyMarkOnce,
|
||||
_n: () => looseToNumber,
|
||||
_s: () => toDisplayString,
|
||||
_l: () => renderList,
|
||||
_t: i => legacyRenderSlot.bind(null, i),
|
||||
_q: () => looseEqual,
|
||||
_i: () => looseIndexOf,
|
||||
_m: i => legacyRenderStatic.bind(null, i),
|
||||
_f: () => resolveFilter,
|
||||
_k: i => legacyCheckKeyCodes.bind(null, i),
|
||||
_b: () => legacyBindObjectProps,
|
||||
_v: () => createTextVNode,
|
||||
_e: () => createCommentVNode,
|
||||
_u: () => legacyresolveScopedSlots,
|
||||
_g: () => legacyBindObjectListeners,
|
||||
_d: () => legacyBindDynamicKeys,
|
||||
_p: () => legacyPrependModifier,
|
||||
} as PublicPropertiesMap
|
||||
|
||||
// v2 render helpers
|
||||
$createElement: () => compatH,
|
||||
_c: () => compatH,
|
||||
_o: () => legacyMarkOnce,
|
||||
_n: () => looseToNumber,
|
||||
_s: () => toDisplayString,
|
||||
_l: () => renderList,
|
||||
_t: i => legacyRenderSlot.bind(null, i),
|
||||
_q: () => looseEqual,
|
||||
_i: () => looseIndexOf,
|
||||
_m: i => legacyRenderStatic.bind(null, i),
|
||||
_f: () => resolveFilter,
|
||||
_k: i => legacyCheckKeyCodes.bind(null, i),
|
||||
_b: () => legacyBindObjectProps,
|
||||
_v: () => createTextVNode,
|
||||
_e: () => createCommentVNode,
|
||||
_u: () => legacyresolveScopedSlots,
|
||||
_g: () => legacyBindObjectListeners,
|
||||
_d: () => legacyBindDynamicKeys,
|
||||
_p: () => legacyPrependModifier,
|
||||
} as PublicPropertiesMap)
|
||||
for (const key in privateAPIs) {
|
||||
map[key] = i => {
|
||||
if (isCompatEnabled(DeprecationTypes.PRIVATE_APIS, i)) {
|
||||
return privateAPIs[key](i)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ import { type Directive, validateDirectiveName } from './directives'
|
|||
import {
|
||||
type ComponentOptions,
|
||||
type ComputedOptions,
|
||||
type MergedComponentOptions,
|
||||
type MethodOptions,
|
||||
applyOptions,
|
||||
resolveMergedOptions,
|
||||
|
@ -524,6 +525,12 @@ export interface ComponentInternalInstance {
|
|||
* @internal
|
||||
*/
|
||||
getCssVars?: () => Record<string, string>
|
||||
|
||||
/**
|
||||
* v2 compat only, for caching mutated $options
|
||||
* @internal
|
||||
*/
|
||||
resolvedOptions?: MergedComponentOptions
|
||||
}
|
||||
|
||||
const emptyAppContext = createAppContext()
|
||||
|
|
|
@ -14,6 +14,7 @@ beforeEach(() => {
|
|||
Vue.configureCompat({
|
||||
MODE: 2,
|
||||
GLOBAL_MOUNT: 'suppress-warning',
|
||||
PRIVATE_APIS: 'suppress-warning',
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -331,3 +332,43 @@ test('INSTANCE_ATTR_CLASS_STYLE', () => {
|
|||
)('Anonymous'),
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('$options mutation', () => {
|
||||
const Comp = {
|
||||
props: ['id'],
|
||||
template: '<div/>',
|
||||
data() {
|
||||
return {
|
||||
foo: '',
|
||||
}
|
||||
},
|
||||
created(this: any) {
|
||||
expect(this.$options.parent).toBeDefined()
|
||||
expect(this.$options.test).toBeUndefined()
|
||||
this.$options.test = this.id
|
||||
expect(this.$options.test).toBe(this.id)
|
||||
},
|
||||
}
|
||||
|
||||
new Vue({
|
||||
template: `<div><Comp id="1"/><Comp id="2"/></div>`,
|
||||
components: { Comp },
|
||||
}).$mount()
|
||||
})
|
||||
|
||||
test('other private APIs', () => {
|
||||
new Vue({
|
||||
created() {
|
||||
expect(this.$createElement).toBeTruthy()
|
||||
},
|
||||
})
|
||||
|
||||
new Vue({
|
||||
compatConfig: {
|
||||
PRIVATE_APIS: false,
|
||||
},
|
||||
created() {
|
||||
expect(this.$createElement).toBeUndefined()
|
||||
},
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue