]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: more compat tweaks
authorEvan You <yyx990803@gmail.com>
Thu, 22 Apr 2021 18:59:54 +0000 (14:59 -0400)
committerEvan You <yyx990803@gmail.com>
Thu, 22 Apr 2021 18:59:54 +0000 (14:59 -0400)
packages/runtime-core/__tests__/componentPublicInstance.spec.ts
packages/runtime-core/src/compat/component.ts
packages/runtime-core/src/compat/global.ts
packages/runtime-core/src/compat/globalConfig.ts
packages/runtime-core/src/compat/instance.ts
packages/runtime-core/src/compat/renderFn.ts
packages/runtime-core/src/componentOptions.ts
packages/runtime-core/src/componentProps.ts
packages/runtime-core/src/componentSlots.ts

index 4a4b56a8473a5ca3307ef610001194db4c3f091b..51dd676e6ed92016623191746da276767d97295d 100644 (file)
@@ -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()
 
index 36188d0cec0fb2d8560401b11bacca53df8aea54..3e89924f35a98604a6ef7f5a058e4c087f2016af 100644 (file)
@@ -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)
   }
 
index 17b71dabd2ab70c101114777b1644b4227e87d48..ca97117c9b7b8a02015fe38a855a27e0caf7f282 100644 (file)
@@ -94,6 +94,14 @@ export type CompatVue = Pick<App, 'version' | 'component' | 'directive'> & {
    * @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
   }
 
index bed3fc39ea97c6f8eae16e565b2a2b88df4c6e6e..168ba87cc3e4da4644c96578811fa04e29b07815 100644 (file)
@@ -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) {
index 1f4dec7c00d7a61d1102435078069e4b165a2fad..bf1d2e2fb01959b52a8d24a4c411cc2f1b3a2f81 100644 (file)
@@ -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,
index b04ca0cda174129d9e649d8db504fb3d470e92a7..afaef39c5ff758b48cd3d7bc561c23ffdbb9d991 100644 (file)
@@ -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) {
index 40755e80d8bc914bbd24eec07d1a8d923228bbea..a9961d753a4a30cb22bd0d79916d6941eadd25e6 100644 (file)
@@ -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
 }
index e7134746c022c8cb30913a7cf0218c05d33868c1..c1568bdab9d6f75e2ddb1204568cc12ad6686037 100644 (file)
@@ -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)
index 1acbd1aa1d6fec69a734b5a00db5169713db5dc7..9fdb0d142dbc9afeec6e74d97d975b6c47e2e68a 100644 (file)
@@ -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.`