wip: more compat tweaks
This commit is contained in:
parent
98bc9a26e9
commit
7e0224aa8c
@ -6,7 +6,7 @@ import {
|
|||||||
createApp,
|
createApp,
|
||||||
shallowReadonly
|
shallowReadonly
|
||||||
} from '@vue/runtime-test'
|
} from '@vue/runtime-test'
|
||||||
import { ComponentInternalInstance } from '../src/component'
|
import { ComponentInternalInstance, ComponentOptions } from '../src/component'
|
||||||
|
|
||||||
describe('component: proxy', () => {
|
describe('component: proxy', () => {
|
||||||
test('data', () => {
|
test('data', () => {
|
||||||
@ -93,7 +93,9 @@ describe('component: proxy', () => {
|
|||||||
expect(instanceProxy.$root).toBe(instance!.root.proxy)
|
expect(instanceProxy.$root).toBe(instance!.root.proxy)
|
||||||
expect(instanceProxy.$emit).toBe(instance!.emit)
|
expect(instanceProxy.$emit).toBe(instance!.emit)
|
||||||
expect(instanceProxy.$el).toBe(instance!.vnode.el)
|
expect(instanceProxy.$el).toBe(instance!.vnode.el)
|
||||||
expect(instanceProxy.$options).toBe(instance!.type)
|
expect(instanceProxy.$options).toBe(
|
||||||
|
(instance!.type as ComponentOptions).__merged
|
||||||
|
)
|
||||||
expect(() => (instanceProxy.$data = {})).toThrow(TypeError)
|
expect(() => (instanceProxy.$data = {})).toThrow(TypeError)
|
||||||
expect(`Attempting to mutate public property "$data"`).toHaveBeenWarned()
|
expect(`Attempting to mutate public property "$data"`).toHaveBeenWarned()
|
||||||
|
|
||||||
|
@ -26,13 +26,18 @@ export function convertLegacyComponent(
|
|||||||
return comp
|
return comp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2.x constructor
|
||||||
|
if (isFunction(comp) && comp.cid) {
|
||||||
|
comp = comp.options
|
||||||
|
}
|
||||||
|
|
||||||
// 2.x async component
|
// 2.x async component
|
||||||
// since after disabling this, plain functions are still valid usage, do not
|
|
||||||
// use softAssert here.
|
|
||||||
if (
|
if (
|
||||||
isFunction(comp) &&
|
isFunction(comp) &&
|
||||||
checkCompatEnabled(DeprecationTypes.COMPONENT_ASYNC, instance, comp)
|
checkCompatEnabled(DeprecationTypes.COMPONENT_ASYNC, instance, comp)
|
||||||
) {
|
) {
|
||||||
|
// since after disabling this, plain functions are still valid usage, do not
|
||||||
|
// use softAssert here.
|
||||||
return convertLegacyAsyncComponent(comp)
|
return convertLegacyAsyncComponent(comp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +94,14 @@ export type CompatVue = Pick<App, 'version' | 'component' | 'directive'> & {
|
|||||||
* @deprecated filters have been removed from Vue 3.
|
* @deprecated filters have been removed from Vue 3.
|
||||||
*/
|
*/
|
||||||
filter(name: string, arg: any): null
|
filter(name: string, arg: any): null
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
cid: number
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
options: ComponentOptions
|
||||||
|
|
||||||
configureCompat: typeof configureCompat
|
configureCompat: typeof configureCompat
|
||||||
}
|
}
|
||||||
@ -109,8 +117,6 @@ export function createCompatVue(
|
|||||||
} as any
|
} as any
|
||||||
|
|
||||||
const singletonApp = createApp({})
|
const singletonApp = createApp({})
|
||||||
// @ts-ignore
|
|
||||||
singletonApp.prototype = singletonApp.config.globalProperties
|
|
||||||
|
|
||||||
function createCompatApp(options: ComponentOptions = {}, Ctor: any) {
|
function createCompatApp(options: ComponentOptions = {}, Ctor: any) {
|
||||||
assertCompatEnabled(DeprecationTypes.GLOBAL_MOUNT, null)
|
assertCompatEnabled(DeprecationTypes.GLOBAL_MOUNT, null)
|
||||||
@ -174,18 +180,26 @@ export function createCompatVue(
|
|||||||
Vue.version = __VERSION__
|
Vue.version = __VERSION__
|
||||||
Vue.config = singletonApp.config
|
Vue.config = singletonApp.config
|
||||||
Vue.nextTick = nextTick
|
Vue.nextTick = nextTick
|
||||||
|
Vue.options = { _base: Vue }
|
||||||
|
|
||||||
Vue.extend = ((options: ComponentOptions = {}) => {
|
let cid = 1
|
||||||
|
Vue.cid = cid
|
||||||
|
|
||||||
|
function extendCtor(this: any, extendOptions: ComponentOptions = {}) {
|
||||||
assertCompatEnabled(DeprecationTypes.GLOBAL_EXTEND, null)
|
assertCompatEnabled(DeprecationTypes.GLOBAL_EXTEND, null)
|
||||||
|
if (isFunction(extendOptions)) {
|
||||||
|
extendOptions = extendOptions.options
|
||||||
|
}
|
||||||
|
|
||||||
|
const Super = this
|
||||||
function SubVue(inlineOptions?: ComponentOptions) {
|
function SubVue(inlineOptions?: ComponentOptions) {
|
||||||
if (!inlineOptions) {
|
if (!inlineOptions) {
|
||||||
return createCompatApp(options, SubVue)
|
return createCompatApp(extendOptions, SubVue)
|
||||||
} else {
|
} else {
|
||||||
return createCompatApp(
|
return createCompatApp(
|
||||||
{
|
{
|
||||||
el: inlineOptions.el,
|
el: inlineOptions.el,
|
||||||
extends: options,
|
extends: extendOptions,
|
||||||
mixins: [inlineOptions]
|
mixins: [inlineOptions]
|
||||||
},
|
},
|
||||||
SubVue
|
SubVue
|
||||||
@ -194,8 +208,20 @@ export function createCompatVue(
|
|||||||
}
|
}
|
||||||
SubVue.prototype = Object.create(Vue.prototype)
|
SubVue.prototype = Object.create(Vue.prototype)
|
||||||
SubVue.prototype.constructor = SubVue
|
SubVue.prototype.constructor = SubVue
|
||||||
|
SubVue.options = mergeOptions(
|
||||||
|
extend({}, Super.options) as ComponentOptions,
|
||||||
|
extendOptions
|
||||||
|
)
|
||||||
|
|
||||||
|
SubVue.options._base = SubVue
|
||||||
|
SubVue.extend = extendCtor.bind(SubVue)
|
||||||
|
SubVue.mixin = Super.mixin
|
||||||
|
SubVue.use = Super.use
|
||||||
|
SubVue.cid = ++cid
|
||||||
return SubVue
|
return SubVue
|
||||||
}) as any
|
}
|
||||||
|
|
||||||
|
Vue.extend = extendCtor.bind(Vue) as any
|
||||||
|
|
||||||
Vue.set = (target, key, value) => {
|
Vue.set = (target, key, value) => {
|
||||||
assertCompatEnabled(DeprecationTypes.GLOBAL_SET, null)
|
assertCompatEnabled(DeprecationTypes.GLOBAL_SET, null)
|
||||||
@ -213,7 +239,11 @@ export function createCompatVue(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vue.use = (p, ...options) => {
|
Vue.use = (p, ...options) => {
|
||||||
singletonApp.use(p, ...options)
|
if (p && isFunction(p.install)) {
|
||||||
|
p.install(Vue as any, ...options)
|
||||||
|
} else if (isFunction(p)) {
|
||||||
|
p(Vue as any, ...options)
|
||||||
|
}
|
||||||
return Vue
|
return Vue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,8 +110,11 @@ export function installLegacyConfigProperties(config: AppConfig) {
|
|||||||
strats.watch = mergeObjectOptions
|
strats.watch = mergeObjectOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeHook(to: Function[] | undefined, from: Function | Function[]) {
|
function mergeHook(
|
||||||
return Array.from(new Set([...(to || []), from]))
|
to: Function[] | Function | undefined,
|
||||||
|
from: Function | Function[]
|
||||||
|
) {
|
||||||
|
return Array.from(new Set([...(isArray(to) ? to : to ? [to] : []), from]))
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeObjectOptions(to: Object | undefined, from: Object | undefined) {
|
function mergeObjectOptions(to: Object | undefined, from: Object | undefined) {
|
||||||
|
@ -32,6 +32,7 @@ import {
|
|||||||
legacyresolveScopedSlots
|
legacyresolveScopedSlots
|
||||||
} from './renderHelpers'
|
} from './renderHelpers'
|
||||||
import { resolveFilter } from '../helpers/resolveAssets'
|
import { resolveFilter } from '../helpers/resolveAssets'
|
||||||
|
import { resolveMergedOptions } from '../componentOptions'
|
||||||
|
|
||||||
export function installCompatInstanceProperties(map: PublicPropertiesMap) {
|
export function installCompatInstanceProperties(map: PublicPropertiesMap) {
|
||||||
const set = (target: any, key: any, val: any) => {
|
const set = (target: any, key: any, val: any) => {
|
||||||
@ -92,9 +93,18 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) {
|
|||||||
$children: getCompatChildren,
|
$children: getCompatChildren,
|
||||||
$listeners: getCompatListeners,
|
$listeners: getCompatListeners,
|
||||||
|
|
||||||
|
// inject parent into $options for compat
|
||||||
|
$options: i => {
|
||||||
|
let res = resolveMergedOptions(i)
|
||||||
|
if (res === i.type) res = i.type.__merged = extend({}, res)
|
||||||
|
res.parent = i.proxy!.$parent
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
|
||||||
// v2 render helpers
|
// v2 render helpers
|
||||||
$createElement: () => compatH,
|
$createElement: () => compatH,
|
||||||
_self: i => i.proxy,
|
_self: i => i.proxy,
|
||||||
|
_uid: i => i.uid,
|
||||||
_c: () => compatH,
|
_c: () => compatH,
|
||||||
_o: () => legacyMarkOnce,
|
_o: () => legacyMarkOnce,
|
||||||
_n: () => toNumber,
|
_n: () => toNumber,
|
||||||
|
@ -3,6 +3,7 @@ import {
|
|||||||
hyphenate,
|
hyphenate,
|
||||||
isArray,
|
isArray,
|
||||||
isObject,
|
isObject,
|
||||||
|
isString,
|
||||||
makeMap,
|
makeMap,
|
||||||
normalizeClass,
|
normalizeClass,
|
||||||
normalizeStyle,
|
normalizeStyle,
|
||||||
@ -304,12 +305,17 @@ export function defineLegacyVNodeProperties(vnode: VNode) {
|
|||||||
if (
|
if (
|
||||||
isCompatEnabled(DeprecationTypes.RENDER_FUNCTION, currentRenderingInstance)
|
isCompatEnabled(DeprecationTypes.RENDER_FUNCTION, currentRenderingInstance)
|
||||||
) {
|
) {
|
||||||
|
const context = currentRenderingInstance
|
||||||
const getInstance = () => vnode.component && vnode.component.proxy
|
const getInstance = () => vnode.component && vnode.component.proxy
|
||||||
let componentOptions: any
|
let componentOptions: any
|
||||||
Object.defineProperties(vnode, {
|
Object.defineProperties(vnode, {
|
||||||
|
tag: { get: () => vnode.type },
|
||||||
|
data: { get: () => vnode.props, set: p => (vnode.props = p) },
|
||||||
elm: { get: () => vnode.el },
|
elm: { get: () => vnode.el },
|
||||||
componentInstance: { get: getInstance },
|
componentInstance: { get: getInstance },
|
||||||
child: { get: getInstance },
|
child: { get: getInstance },
|
||||||
|
text: { get: () => (isString(vnode.children) ? vnode.children : null) },
|
||||||
|
context: { get: () => context && context.proxy },
|
||||||
componentOptions: {
|
componentOptions: {
|
||||||
get: () => {
|
get: () => {
|
||||||
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
|
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
|
||||||
|
@ -509,6 +509,10 @@ export function applyOptions(
|
|||||||
deferredProvide: (Data | Function)[] = [],
|
deferredProvide: (Data | Function)[] = [],
|
||||||
asMixin: boolean = false
|
asMixin: boolean = false
|
||||||
) {
|
) {
|
||||||
|
if (__COMPAT__ && isFunction(options)) {
|
||||||
|
options = options.options
|
||||||
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
// composition
|
// composition
|
||||||
mixins,
|
mixins,
|
||||||
@ -1005,6 +1009,10 @@ export function mergeOptions(
|
|||||||
from: any,
|
from: any,
|
||||||
instance?: ComponentInternalInstance
|
instance?: ComponentInternalInstance
|
||||||
) {
|
) {
|
||||||
|
if (__COMPAT__ && isFunction(from)) {
|
||||||
|
from = from.options
|
||||||
|
}
|
||||||
|
|
||||||
const strats = instance && instance.appContext.config.optionMergeStrategies
|
const strats = instance && instance.appContext.config.optionMergeStrategies
|
||||||
const { mixins, extends: extendsOptions } = from
|
const { mixins, extends: extendsOptions } = from
|
||||||
|
|
||||||
@ -1019,4 +1027,5 @@ export function mergeOptions(
|
|||||||
to[key] = from[key]
|
to[key] = from[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return to
|
||||||
}
|
}
|
||||||
|
@ -429,6 +429,9 @@ export function normalizePropsOptions(
|
|||||||
let hasExtends = false
|
let hasExtends = false
|
||||||
if (__FEATURE_OPTIONS_API__ && !isFunction(comp)) {
|
if (__FEATURE_OPTIONS_API__ && !isFunction(comp)) {
|
||||||
const extendProps = (raw: ComponentOptions) => {
|
const extendProps = (raw: ComponentOptions) => {
|
||||||
|
if (__COMPAT__ && isFunction(raw)) {
|
||||||
|
raw = raw.options
|
||||||
|
}
|
||||||
hasExtends = true
|
hasExtends = true
|
||||||
const [props, keys] = normalizePropsOptions(raw, appContext, true)
|
const [props, keys] = normalizePropsOptions(raw, appContext, true)
|
||||||
extend(normalized, props)
|
extend(normalized, props)
|
||||||
|
@ -107,7 +107,11 @@ const normalizeVNodeSlots = (
|
|||||||
instance: ComponentInternalInstance,
|
instance: ComponentInternalInstance,
|
||||||
children: VNodeNormalizedChildren
|
children: VNodeNormalizedChildren
|
||||||
) => {
|
) => {
|
||||||
if (__DEV__ && !isKeepAlive(instance.vnode)) {
|
if (
|
||||||
|
__DEV__ &&
|
||||||
|
!isKeepAlive(instance.vnode) &&
|
||||||
|
!(__COMPAT__ && isCompatEnabled(DeprecationTypes.RENDER_FUNCTION, instance))
|
||||||
|
) {
|
||||||
warn(
|
warn(
|
||||||
`Non-function value encountered for default slot. ` +
|
`Non-function value encountered for default slot. ` +
|
||||||
`Prefer function slots for better performance.`
|
`Prefer function slots for better performance.`
|
||||||
|
Loading…
Reference in New Issue
Block a user