From: Evan You Date: Thu, 22 Apr 2021 18:59:54 +0000 (-0400) Subject: wip: more compat tweaks X-Git-Tag: v3.1.0-beta.1~59^2~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7e0224aa8c77ad261fb251373b2a487d6e1ba085;p=thirdparty%2Fvuejs%2Fcore.git wip: more compat tweaks --- diff --git a/packages/runtime-core/__tests__/componentPublicInstance.spec.ts b/packages/runtime-core/__tests__/componentPublicInstance.spec.ts index 4a4b56a847..51dd676e6e 100644 --- a/packages/runtime-core/__tests__/componentPublicInstance.spec.ts +++ b/packages/runtime-core/__tests__/componentPublicInstance.spec.ts @@ -6,7 +6,7 @@ import { createApp, shallowReadonly } from '@vue/runtime-test' -import { ComponentInternalInstance } from '../src/component' +import { ComponentInternalInstance, ComponentOptions } from '../src/component' describe('component: proxy', () => { test('data', () => { @@ -93,7 +93,9 @@ describe('component: proxy', () => { expect(instanceProxy.$root).toBe(instance!.root.proxy) expect(instanceProxy.$emit).toBe(instance!.emit) 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(`Attempting to mutate public property "$data"`).toHaveBeenWarned() diff --git a/packages/runtime-core/src/compat/component.ts b/packages/runtime-core/src/compat/component.ts index 36188d0cec..3e89924f35 100644 --- a/packages/runtime-core/src/compat/component.ts +++ b/packages/runtime-core/src/compat/component.ts @@ -26,13 +26,18 @@ export function convertLegacyComponent( return comp } + // 2.x constructor + if (isFunction(comp) && comp.cid) { + comp = comp.options + } + // 2.x async component - // since after disabling this, plain functions are still valid usage, do not - // use softAssert here. if ( isFunction(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) } diff --git a/packages/runtime-core/src/compat/global.ts b/packages/runtime-core/src/compat/global.ts index 17b71dabd2..ca97117c9b 100644 --- a/packages/runtime-core/src/compat/global.ts +++ b/packages/runtime-core/src/compat/global.ts @@ -94,6 +94,14 @@ export type CompatVue = Pick & { * @deprecated filters have been removed from Vue 3. */ filter(name: string, arg: any): null + /** + * @internal + */ + cid: number + /** + * @internal + */ + options: ComponentOptions configureCompat: typeof configureCompat } @@ -109,8 +117,6 @@ export function createCompatVue( } as any const singletonApp = createApp({}) - // @ts-ignore - singletonApp.prototype = singletonApp.config.globalProperties function createCompatApp(options: ComponentOptions = {}, Ctor: any) { assertCompatEnabled(DeprecationTypes.GLOBAL_MOUNT, null) @@ -174,18 +180,26 @@ export function createCompatVue( Vue.version = __VERSION__ Vue.config = singletonApp.config Vue.nextTick = nextTick + Vue.options = { _base: Vue } + + let cid = 1 + Vue.cid = cid - Vue.extend = ((options: ComponentOptions = {}) => { + function extendCtor(this: any, extendOptions: ComponentOptions = {}) { assertCompatEnabled(DeprecationTypes.GLOBAL_EXTEND, null) + if (isFunction(extendOptions)) { + extendOptions = extendOptions.options + } + const Super = this function SubVue(inlineOptions?: ComponentOptions) { if (!inlineOptions) { - return createCompatApp(options, SubVue) + return createCompatApp(extendOptions, SubVue) } else { return createCompatApp( { el: inlineOptions.el, - extends: options, + extends: extendOptions, mixins: [inlineOptions] }, SubVue @@ -194,8 +208,20 @@ export function createCompatVue( } SubVue.prototype = Object.create(Vue.prototype) 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 - }) as any + } + + Vue.extend = extendCtor.bind(Vue) as any Vue.set = (target, key, value) => { assertCompatEnabled(DeprecationTypes.GLOBAL_SET, null) @@ -213,7 +239,11 @@ export function createCompatVue( } 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 } diff --git a/packages/runtime-core/src/compat/globalConfig.ts b/packages/runtime-core/src/compat/globalConfig.ts index bed3fc39ea..168ba87cc3 100644 --- a/packages/runtime-core/src/compat/globalConfig.ts +++ b/packages/runtime-core/src/compat/globalConfig.ts @@ -110,8 +110,11 @@ export function installLegacyConfigProperties(config: AppConfig) { strats.watch = mergeObjectOptions } -function mergeHook(to: Function[] | undefined, from: Function | Function[]) { - return Array.from(new Set([...(to || []), from])) +function mergeHook( + 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) { diff --git a/packages/runtime-core/src/compat/instance.ts b/packages/runtime-core/src/compat/instance.ts index 1f4dec7c00..bf1d2e2fb0 100644 --- a/packages/runtime-core/src/compat/instance.ts +++ b/packages/runtime-core/src/compat/instance.ts @@ -32,6 +32,7 @@ import { legacyresolveScopedSlots } from './renderHelpers' import { resolveFilter } from '../helpers/resolveAssets' +import { resolveMergedOptions } from '../componentOptions' export function installCompatInstanceProperties(map: PublicPropertiesMap) { const set = (target: any, key: any, val: any) => { @@ -92,9 +93,18 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) { $children: getCompatChildren, $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 $createElement: () => compatH, _self: i => i.proxy, + _uid: i => i.uid, _c: () => compatH, _o: () => legacyMarkOnce, _n: () => toNumber, diff --git a/packages/runtime-core/src/compat/renderFn.ts b/packages/runtime-core/src/compat/renderFn.ts index b04ca0cda1..afaef39c5f 100644 --- a/packages/runtime-core/src/compat/renderFn.ts +++ b/packages/runtime-core/src/compat/renderFn.ts @@ -3,6 +3,7 @@ import { hyphenate, isArray, isObject, + isString, makeMap, normalizeClass, normalizeStyle, @@ -304,12 +305,17 @@ export function defineLegacyVNodeProperties(vnode: VNode) { if ( isCompatEnabled(DeprecationTypes.RENDER_FUNCTION, currentRenderingInstance) ) { + const context = currentRenderingInstance const getInstance = () => vnode.component && vnode.component.proxy let componentOptions: any Object.defineProperties(vnode, { + tag: { get: () => vnode.type }, + data: { get: () => vnode.props, set: p => (vnode.props = p) }, elm: { get: () => vnode.el }, componentInstance: { get: getInstance }, child: { get: getInstance }, + text: { get: () => (isString(vnode.children) ? vnode.children : null) }, + context: { get: () => context && context.proxy }, componentOptions: { get: () => { if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) { diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 40755e80d8..a9961d753a 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -509,6 +509,10 @@ export function applyOptions( deferredProvide: (Data | Function)[] = [], asMixin: boolean = false ) { + if (__COMPAT__ && isFunction(options)) { + options = options.options + } + const { // composition mixins, @@ -1005,6 +1009,10 @@ export function mergeOptions( from: any, instance?: ComponentInternalInstance ) { + if (__COMPAT__ && isFunction(from)) { + from = from.options + } + const strats = instance && instance.appContext.config.optionMergeStrategies const { mixins, extends: extendsOptions } = from @@ -1019,4 +1027,5 @@ export function mergeOptions( to[key] = from[key] } } + return to } diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index e7134746c0..c1568bdab9 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -429,6 +429,9 @@ export function normalizePropsOptions( let hasExtends = false if (__FEATURE_OPTIONS_API__ && !isFunction(comp)) { const extendProps = (raw: ComponentOptions) => { + if (__COMPAT__ && isFunction(raw)) { + raw = raw.options + } hasExtends = true const [props, keys] = normalizePropsOptions(raw, appContext, true) extend(normalized, props) diff --git a/packages/runtime-core/src/componentSlots.ts b/packages/runtime-core/src/componentSlots.ts index 1acbd1aa1d..9fdb0d142d 100644 --- a/packages/runtime-core/src/componentSlots.ts +++ b/packages/runtime-core/src/componentSlots.ts @@ -107,7 +107,11 @@ const normalizeVNodeSlots = ( instance: ComponentInternalInstance, children: VNodeNormalizedChildren ) => { - if (__DEV__ && !isKeepAlive(instance.vnode)) { + if ( + __DEV__ && + !isKeepAlive(instance.vnode) && + !(__COMPAT__ && isCompatEnabled(DeprecationTypes.RENDER_FUNCTION, instance)) + ) { warn( `Non-function value encountered for default slot. ` + `Prefer function slots for better performance.`