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,
|
DeprecationTypes,
|
||||||
assertCompatEnabled,
|
assertCompatEnabled,
|
||||||
isCompatEnabled,
|
isCompatEnabled,
|
||||||
|
warnDeprecation,
|
||||||
} from './compatConfig'
|
} from './compatConfig'
|
||||||
import { off, on, once } from './instanceEventEmitter'
|
import { off, on, once } from './instanceEventEmitter'
|
||||||
import { getCompatListeners } from './instanceListeners'
|
import { getCompatListeners } from './instanceListeners'
|
||||||
|
@ -121,22 +122,42 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) {
|
||||||
|
|
||||||
$children: getCompatChildren,
|
$children: getCompatChildren,
|
||||||
$listeners: getCompatListeners,
|
$listeners: getCompatListeners,
|
||||||
} as PublicPropertiesMap)
|
|
||||||
|
|
||||||
/* istanbul ignore if */
|
|
||||||
if (isCompatEnabled(DeprecationTypes.PRIVATE_APIS, null)) {
|
|
||||||
extend(map, {
|
|
||||||
// needed by many libs / render fns
|
|
||||||
$vnode: i => i.vnode,
|
|
||||||
|
|
||||||
// inject additional properties into $options for compat
|
// inject additional properties into $options for compat
|
||||||
// e.g. vuex needs this.$options.parent
|
// e.g. vuex needs this.$options.parent
|
||||||
$options: i => {
|
$options: i => {
|
||||||
const res = extend({}, resolveMergedOptions(i))
|
if (!isCompatEnabled(DeprecationTypes.PRIVATE_APIS, i)) {
|
||||||
res.parent = i.proxy!.$parent
|
return resolveMergedOptions(i)
|
||||||
res.propsData = i.vnode.props
|
}
|
||||||
|
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
|
return res
|
||||||
},
|
},
|
||||||
|
} as PublicPropertiesMap)
|
||||||
|
|
||||||
|
const privateAPIs = {
|
||||||
|
// needed by many libs / render fns
|
||||||
|
$vnode: i => i.vnode,
|
||||||
|
|
||||||
// some private properties that are likely accessed...
|
// some private properties that are likely accessed...
|
||||||
_self: i => i.proxy,
|
_self: i => i.proxy,
|
||||||
|
@ -165,6 +186,13 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) {
|
||||||
_g: () => legacyBindObjectListeners,
|
_g: () => legacyBindObjectListeners,
|
||||||
_d: () => legacyBindDynamicKeys,
|
_d: () => legacyBindDynamicKeys,
|
||||||
_p: () => legacyPrependModifier,
|
_p: () => legacyPrependModifier,
|
||||||
} as PublicPropertiesMap)
|
} 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 {
|
import {
|
||||||
type ComponentOptions,
|
type ComponentOptions,
|
||||||
type ComputedOptions,
|
type ComputedOptions,
|
||||||
|
type MergedComponentOptions,
|
||||||
type MethodOptions,
|
type MethodOptions,
|
||||||
applyOptions,
|
applyOptions,
|
||||||
resolveMergedOptions,
|
resolveMergedOptions,
|
||||||
|
@ -524,6 +525,12 @@ export interface ComponentInternalInstance {
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
getCssVars?: () => Record<string, string>
|
getCssVars?: () => Record<string, string>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v2 compat only, for caching mutated $options
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
resolvedOptions?: MergedComponentOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
const emptyAppContext = createAppContext()
|
const emptyAppContext = createAppContext()
|
||||||
|
|
|
@ -14,6 +14,7 @@ beforeEach(() => {
|
||||||
Vue.configureCompat({
|
Vue.configureCompat({
|
||||||
MODE: 2,
|
MODE: 2,
|
||||||
GLOBAL_MOUNT: 'suppress-warning',
|
GLOBAL_MOUNT: 'suppress-warning',
|
||||||
|
PRIVATE_APIS: 'suppress-warning',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -331,3 +332,43 @@ test('INSTANCE_ATTR_CLASS_STYLE', () => {
|
||||||
)('Anonymous'),
|
)('Anonymous'),
|
||||||
).toHaveBeenWarned()
|
).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