]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: restructure compat code + global api alignment
authorEvan You <yyx990803@gmail.com>
Mon, 5 Apr 2021 21:09:22 +0000 (17:09 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 7 Apr 2021 20:19:24 +0000 (16:19 -0400)
13 files changed:
jest.config.js
packages/runtime-core/src/apiCreateApp.ts
packages/runtime-core/src/compat/deprecations.ts [new file with mode: 0644]
packages/runtime-core/src/compat/global.ts [new file with mode: 0644]
packages/runtime-core/src/compat/globalConfig.ts [new file with mode: 0644]
packages/runtime-core/src/compat/globalMount.ts [new file with mode: 0644]
packages/runtime-core/src/componentPublicInstance.ts
packages/runtime-core/src/index.ts
packages/runtime-dom/src/index.ts
packages/shared/src/deprecations.ts [deleted file]
packages/shared/src/index.ts
packages/vue-compat/src/apiGlobal.ts [deleted file]
packages/vue-compat/src/index.ts

index e8507b5db0f71abcee3bfe9b5cc5bb423eb05379..7ec66b39d15e373477b6b33a2d93aae7d9eb678a 100644 (file)
@@ -12,7 +12,8 @@ module.exports = {
     __NODE_JS__: true,
     __FEATURE_OPTIONS_API__: true,
     __FEATURE_SUSPENSE__: true,
-    __FEATURE_PROD_DEVTOOLS__: false
+    __FEATURE_PROD_DEVTOOLS__: false,
+    __COMPAT__: true
   },
   coverageDirectory: 'coverage',
   coverageReporters: ['html', 'lcov', 'text'],
index 8ef0a2a22c64cafec8fb2657d53d18fd630c0ec0..5af5babd75118eb3a39e21dc511ce340affc03ad 100644 (file)
@@ -2,10 +2,7 @@ import {
   ConcreteComponent,
   Data,
   validateComponentName,
-  Component,
-  createComponentInstance,
-  setupComponent,
-  finishComponentSetup
+  Component
 } from './component'
 import { ComponentOptions } from './componentOptions'
 import { ComponentPublicInstance } from './componentPublicInstance'
@@ -16,14 +13,10 @@ import { warn } from './warning'
 import { createVNode, cloneVNode, VNode } from './vnode'
 import { RootHydrateFunction } from './hydration'
 import { devtoolsInitApp, devtoolsUnmountApp } from './devtools'
+import { isFunction, NO, isObject } from '@vue/shared'
 import { version } from '.'
-import {
-  isFunction,
-  NO,
-  isObject,
-  warnDeprecation,
-  DeprecationTypes
-} from '@vue/shared'
+import { installCompatMount } from './compat/globalMount'
+import { installLegacyConfigTraps } from './compat/globalConfig'
 
 export interface App<HostElement = any> {
   version: string
@@ -313,126 +306,8 @@ export function createAppAPI<HostElement>(
     })
 
     if (__COMPAT__) {
-      /**
-       * Vue 2 supports the behavior of creating a component instance but not
-       * mounting it, which is no longer possible in Vue 3 - this internal
-       * function simulates that behavior.
-       */
-      app._createRoot = options => {
-        const vnode = createVNode(
-          rootComponent as ConcreteComponent,
-          options.propsData || null
-        )
-        vnode.appContext = context
-
-        const hasNoRender =
-          !isFunction(rootComponent) &&
-          !rootComponent.render &&
-          !rootComponent.template
-        const emptyRender = () => {}
-
-        // create root instance
-        const instance = createComponentInstance(vnode, null, null)
-        // suppress "missing render fn" warning since it can't be determined
-        // until $mount is called
-        if (hasNoRender) {
-          instance.render = emptyRender
-        }
-        setupComponent(instance, __NODE_JS__)
-        vnode.component = instance
-
-        // $mount & $destroy
-        // these are defined on ctx and picked up by the $mount/$destroy
-        // public property getters on the instance proxy.
-        // Note: the following assumes DOM environment since the compat build
-        // only targets web. It essentially includes logic for app.mount from
-        // both runtime-core AND runtime-dom.
-        instance.ctx._compat_mount = (selectorOrEl: string | Element) => {
-          if (isMounted) {
-            __DEV__ && warn(`Root instance is already mounted.`)
-            return
-          }
-
-          let container: Element
-          if (typeof selectorOrEl === 'string') {
-            // eslint-disable-next-line
-            const result = document.querySelector(selectorOrEl)
-            if (!result) {
-              __DEV__ &&
-                warn(
-                  `Failed to mount root instance: selector "${selectorOrEl}" returned null.`
-                )
-              return
-            }
-            container = result
-          } else {
-            if (!selectorOrEl) {
-              __DEV__ &&
-                warn(
-                  `Failed to mount root instance: invalid mount target ${selectorOrEl}.`
-                )
-              return
-            }
-            container = selectorOrEl
-          }
-
-          const isSVG = container instanceof SVGElement
-
-          // HMR root reload
-          if (__DEV__) {
-            context.reload = () => {
-              const cloned = cloneVNode(vnode)
-              // compat mode will use instance if not reset to null
-              cloned.component = null
-              render(cloned, container, isSVG)
-            }
-          }
-
-          // resolve in-DOM template if component did not provide render
-          // and no setup/mixin render functions are provided (by checking
-          // that the instance is still using the placeholder render fn)
-          if (hasNoRender && instance.render === emptyRender) {
-            // root directives check
-            if (__DEV__) {
-              for (let i = 0; i < container.attributes.length; i++) {
-                const attr = container.attributes[i]
-                if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) {
-                  warnDeprecation(DeprecationTypes.DOM_TEMPLATE_MOUNT)
-                  break
-                }
-              }
-            }
-            instance.render = null
-            ;(rootComponent as ComponentOptions).template = container.innerHTML
-            finishComponentSetup(instance, __NODE_JS__, true /* skip options */)
-          }
-
-          // clear content before mounting
-          container.innerHTML = ''
-
-          // TODO hydration
-          render(vnode, container, isSVG)
-
-          if (container instanceof Element) {
-            container.removeAttribute('v-cloak')
-            container.setAttribute('data-v-app', '')
-          }
-
-          isMounted = true
-          app._container = container
-          // for devtools and telemetry
-          ;(container as any).__vue_app__ = app
-          if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
-            devtoolsInitApp(app, version)
-          }
-
-          return instance.proxy!
-        }
-
-        instance.ctx._compat_destroy = app.unmount
-
-        return instance.proxy!
-      }
+      installCompatMount(app, context, render, hydrate)
+      installLegacyConfigTraps(app.config)
     }
 
     return app
diff --git a/packages/runtime-core/src/compat/deprecations.ts b/packages/runtime-core/src/compat/deprecations.ts
new file mode 100644 (file)
index 0000000..ae5a39b
--- /dev/null
@@ -0,0 +1,91 @@
+import { isRuntimeOnly } from '../component'
+
+export const enum DeprecationTypes {
+  DOM_TEMPLATE_MOUNT,
+  $MOUNT,
+  $DESTROY,
+
+  CONFIG_SILENT,
+  CONFIG_DEVTOOLS,
+  CONFIG_KEY_CODES,
+  CONFIG_PRODUCTION_TIP,
+  CONFIG_IGNORED_ELEMENTS
+}
+
+type DeprecationData = {
+  message: string | (() => string)
+  link?: string
+}
+
+const deprecations: Record<DeprecationTypes, DeprecationData> = {
+  [DeprecationTypes.DOM_TEMPLATE_MOUNT]: {
+    message:
+      `Vue detected directives on the mount container. ` +
+      `In Vue 3, the container is no longer considered part of the template ` +
+      `and will not be processed/replaced.`,
+    link: `https://v3.vuejs.org/guide/migration/mount-changes.html`
+  },
+
+  [DeprecationTypes.$MOUNT]: {
+    message:
+      `vm.$mount() has been removed. ` +
+      `Use createApp(RootComponent).mount() instead.`,
+    link: `https://v3.vuejs.org/guide/migration/global-api.html#mounting-app-instance`
+  },
+
+  [DeprecationTypes.$DESTROY]: {
+    message: `vm.$destroy() has been removed. Use app.unmount() instead.`,
+    link: `https://v3.vuejs.org/api/application-api.html#unmount`
+  },
+
+  [DeprecationTypes.CONFIG_SILENT]: {
+    message:
+      `config.silent has been removed because it is not good practice to ` +
+      `intentionally suppress warnings. You can use your browser console's ` +
+      `filter features to focus on relevant messages.`
+  },
+
+  [DeprecationTypes.CONFIG_DEVTOOLS]: {
+    message:
+      `config.devtools has been removed. To enable devtools for ` +
+      `production, configure the __VUE_PROD_DEVTOOLS__ compile-time flag.`,
+    link: `https://github.com/vuejs/vue-next/tree/master/packages/vue#bundler-build-feature-flags`
+  },
+
+  [DeprecationTypes.CONFIG_KEY_CODES]: {
+    message:
+      `config.keyCodes has been removed. ` +
+      `In Vue 3, you can directly use the kebab-case key names as v-on modifiers.`,
+    link: `https://v3.vuejs.org/guide/migration/keycode-modifiers.html`
+  },
+
+  [DeprecationTypes.CONFIG_PRODUCTION_TIP]: {
+    message: `config.productionTip has been removed.`,
+    link: `https://v3.vuejs.org/guide/migration/global-api.html#config-productiontip-removed`
+  },
+
+  [DeprecationTypes.CONFIG_IGNORED_ELEMENTS]: {
+    message: () => {
+      let msg = `config.ignoredElements has been removed.`
+      if (isRuntimeOnly()) {
+        msg += ` Pass the "isCustomElement" option to @vue/compiler-dom instead.`
+      } else {
+        msg += ` Use config.isCustomElement instead.`
+      }
+      return msg
+    },
+    link: `https://v3.vuejs.org/guide/migration/global-api.html#config-ignoredelements-is-now-config-iscustomelement`
+  }
+}
+
+export function warnDeprecation(key: DeprecationTypes) {
+  if (!__COMPAT__ || !__DEV__) {
+    return
+  }
+  const { message, link } = deprecations[key]
+  console.warn(
+    `[Vue Deprecation]: ${typeof message === 'function' ? message() : message}${
+      link ? `\nFor more details, see ${link}` : ``
+    }`
+  )
+}
diff --git a/packages/runtime-core/src/compat/global.ts b/packages/runtime-core/src/compat/global.ts
new file mode 100644 (file)
index 0000000..5088ddf
--- /dev/null
@@ -0,0 +1,171 @@
+import { reactive } from '@vue/reactivity'
+import { extend } from '@vue/shared'
+import { createApp } from '../../../runtime-dom/src'
+import { App, AppConfig, Plugin } from '../apiCreateApp'
+import { defineComponent } from '../apiDefineComponent'
+import { Component, ComponentOptions, isRuntimeOnly } from '../component'
+import { RenderFunction } from '../componentOptions'
+import { ComponentPublicInstance } from '../componentPublicInstance'
+import { Directive } from '../directives'
+import { nextTick } from '../scheduler'
+
+/**
+ * @deprecated the default `Vue` export has been removed in Vue 3. The type for
+ * the default export is provided only for migration purposes. Please use
+ * named imports instead - e.g. `import { createApp } from 'vue'`.
+ */
+export type CompatVue = Pick<App, 'version' | 'component' | 'directive'> & {
+  // no inference here since these types are not meant for actual use - they
+  // are merely here to provide type checks for internal implementation and
+  // information for migration.
+  new (options?: ComponentOptions): ComponentPublicInstance
+
+  version: string
+  config: AppConfig
+
+  extend: typeof defineComponent
+  nextTick: typeof nextTick
+
+  use(plugin: Plugin, ...options: any[]): CompatVue
+  mixin(mixin: ComponentOptions): CompatVue
+
+  component(name: string): Component | undefined
+  component(name: string, component: Component): CompatVue
+  directive(name: string): Directive | undefined
+  directive(name: string, directive: Directive): CompatVue
+
+  compile(template: string): RenderFunction
+
+  /**
+   * @deprecated Vue 3 no longer needs set() for adding new properties.
+   */
+  set(target: any, key: string | number | symbol, value: any): void
+  /**
+   * @deprecated Vue 3 no longer needs delete() for property deletions.
+   */
+  delete(target: any, key: string | number | symbol): void
+  /**
+   * @deprecated use `reactive` instead.
+   */
+  observable: typeof reactive
+  /**
+   * @deprecated filters have been removed from Vue 3.
+   */
+  filter(name: string, arg: any): null
+}
+
+export let isCopyingConfig = false
+
+// Legacy global Vue constructor
+export function createCompatVue(): CompatVue {
+  if (!__COMPAT__) {
+    // @ts-ignore this function will never be called in non-compat mode
+    return
+  }
+
+  const Vue: CompatVue = function Vue(options: ComponentOptions = {}) {
+    return createCompatApp(options, Vue)
+  } as any
+
+  const singletonApp = createApp({})
+
+  function createCompatApp(options: ComponentOptions = {}, Ctor: any) {
+    const app = createApp(options)
+
+    // copy over global config mutations
+    isCopyingConfig = true
+    for (const key in singletonApp.config) {
+      if (
+        key !== 'isNativeTag' &&
+        !(key === 'isCustomElement' && isRuntimeOnly())
+      ) {
+        // @ts-ignore
+        app.config[key] = singletonApp.config[key]
+      }
+    }
+    isCopyingConfig = false
+
+    // copy prototype augmentations as config.globalProperties
+    for (const key in Ctor.prototype) {
+      app.config.globalProperties[key] = Ctor.prototype[key]
+    }
+
+    const vm = app._createRoot!(options)
+    if (options.el) {
+      return (vm as any).$mount(options.el)
+    } else {
+      return vm
+    }
+  }
+
+  Vue.version = __VERSION__
+  Vue.config = singletonApp.config
+
+  Vue.extend = ((options: ComponentOptions = {}) => {
+    function SubVue(inlineOptions?: ComponentOptions) {
+      if (!inlineOptions) {
+        return createCompatApp(options, SubVue)
+      } else {
+        return createCompatApp(
+          {
+            el: inlineOptions.el,
+            extends: options,
+            mixins: [inlineOptions]
+          },
+          SubVue
+        )
+      }
+    }
+    SubVue.prototype = Object.create(Vue.prototype)
+    SubVue.prototype.constructor = SubVue
+    return SubVue
+  }) as any
+
+  Vue.nextTick = nextTick
+
+  Vue.set = (target, key, value) => {
+    // TODO deprecation warnings
+    target[key] = value
+  }
+  Vue.delete = (target, key) => {
+    // TODO deprecation warnings
+    delete target[key]
+  }
+  // TODO wrap with deprecation warning
+  Vue.observable = reactive
+
+  Vue.use = (p, ...options) => {
+    singletonApp.use(p, ...options)
+    return Vue
+  }
+
+  Vue.mixin = m => {
+    singletonApp.mixin(m)
+    return Vue
+  }
+
+  Vue.component = ((name: string, comp: any) => {
+    if (comp) {
+      singletonApp.component(name, comp)
+      return Vue
+    } else {
+      return singletonApp.component(name)
+    }
+  }) as any
+
+  Vue.directive = ((name: string, dir: any) => {
+    if (dir) {
+      singletonApp.directive(name, dir)
+      return Vue
+    } else {
+      return singletonApp.directive(name)
+    }
+  }) as any
+
+  Vue.filter = ((name: string, filter: any) => {
+    // TODO deprecation warning
+    // TODO compiler warning for filters (maybe behavior compat?)
+  }) as any
+
+  return Vue
+}
diff --git a/packages/runtime-core/src/compat/globalConfig.ts b/packages/runtime-core/src/compat/globalConfig.ts
new file mode 100644 (file)
index 0000000..e8eafae
--- /dev/null
@@ -0,0 +1,57 @@
+import { AppConfig } from '../apiCreateApp'
+import { DeprecationTypes, warnDeprecation } from './deprecations'
+import { isCopyingConfig } from './global'
+
+// legacy config warnings
+export type LegacyConfig = {
+  /**
+   * @deprecated `config.silent` option has been removed
+   */
+  silent?: boolean
+  /**
+   * @deprecated use __VUE_PROD_DEVTOOLS__ compile-time feature flag instead
+   * https://github.com/vuejs/vue-next/tree/master/packages/vue#bundler-build-feature-flags
+   */
+  devtools?: boolean
+  /**
+   * @deprecated use `config.isCustomElement` instead
+   * https://v3.vuejs.org/guide/migration/global-api.html#config-ignoredelements-is-now-config-iscustomelement
+   */
+  ignoredElements?: (string | RegExp)[]
+  /**
+   * @deprecated
+   * https://v3.vuejs.org/guide/migration/keycode-modifiers.html
+   */
+  keyCodes?: Record<string, number | number[]>
+  /**
+   * @deprecated
+   * https://v3.vuejs.org/guide/migration/global-api.html#config-productiontip-removed
+   */
+  productionTip?: boolean
+}
+
+export function installLegacyConfigTraps(config: AppConfig) {
+  const legacyConfigOptions: Record<string, DeprecationTypes> = {
+    silent: DeprecationTypes.CONFIG_SILENT,
+    devtools: DeprecationTypes.CONFIG_DEVTOOLS,
+    ignoredElements: DeprecationTypes.CONFIG_IGNORED_ELEMENTS,
+    keyCodes: DeprecationTypes.CONFIG_KEY_CODES,
+    productionTip: DeprecationTypes.CONFIG_PRODUCTION_TIP
+  }
+
+  Object.keys(legacyConfigOptions).forEach(key => {
+    let val = (config as any)[key]
+    Object.defineProperty(config, key, {
+      enumerable: true,
+      get() {
+        return val
+      },
+      set(newVal) {
+        if (!isCopyingConfig) {
+          warnDeprecation(legacyConfigOptions[key])
+        }
+        val = newVal
+      }
+    })
+  })
+}
diff --git a/packages/runtime-core/src/compat/globalMount.ts b/packages/runtime-core/src/compat/globalMount.ts
new file mode 100644 (file)
index 0000000..0e30d6c
--- /dev/null
@@ -0,0 +1,141 @@
+import { isFunction } from '@vue/shared'
+import { App, AppContext } from '../apiCreateApp'
+import {
+  ComponentOptions,
+  createComponentInstance,
+  finishComponentSetup,
+  setupComponent
+} from '../component'
+import { devtoolsInitApp } from '../devtools'
+import { RootHydrateFunction } from '../hydration'
+import { RootRenderFunction } from '../renderer'
+import { cloneVNode, createVNode } from '../vnode'
+import { warn } from '../warning'
+import { version } from '..'
+import { DeprecationTypes, warnDeprecation } from './deprecations'
+
+export function installCompatMount(
+  app: App,
+  context: AppContext,
+  render: RootRenderFunction,
+  hydrate?: RootHydrateFunction
+) {
+  let isMounted = false
+
+  /**
+   * Vue 2 supports the behavior of creating a component instance but not
+   * mounting it, which is no longer possible in Vue 3 - this internal
+   * function simulates that behavior.
+   */
+  app._createRoot = options => {
+    const component = app._component
+    const vnode = createVNode(component, options.propsData || null)
+    vnode.appContext = context
+
+    const hasNoRender =
+      !isFunction(component) && !component.render && !component.template
+    const emptyRender = () => {}
+
+    // create root instance
+    const instance = createComponentInstance(vnode, null, null)
+    // suppress "missing render fn" warning since it can't be determined
+    // until $mount is called
+    if (hasNoRender) {
+      instance.render = emptyRender
+    }
+    setupComponent(instance, __NODE_JS__)
+    vnode.component = instance
+
+    // $mount & $destroy
+    // these are defined on ctx and picked up by the $mount/$destroy
+    // public property getters on the instance proxy.
+    // Note: the following assumes DOM environment since the compat build
+    // only targets web. It essentially includes logic for app.mount from
+    // both runtime-core AND runtime-dom.
+    instance.ctx._compat_mount = (selectorOrEl: string | Element) => {
+      if (isMounted) {
+        __DEV__ && warn(`Root instance is already mounted.`)
+        return
+      }
+
+      let container: Element
+      if (typeof selectorOrEl === 'string') {
+        // eslint-disable-next-line
+        const result = document.querySelector(selectorOrEl)
+        if (!result) {
+          __DEV__ &&
+            warn(
+              `Failed to mount root instance: selector "${selectorOrEl}" returned null.`
+            )
+          return
+        }
+        container = result
+      } else {
+        if (!selectorOrEl) {
+          __DEV__ &&
+            warn(
+              `Failed to mount root instance: invalid mount target ${selectorOrEl}.`
+            )
+          return
+        }
+        container = selectorOrEl
+      }
+
+      const isSVG = container instanceof SVGElement
+
+      // HMR root reload
+      if (__DEV__) {
+        context.reload = () => {
+          const cloned = cloneVNode(vnode)
+          // compat mode will use instance if not reset to null
+          cloned.component = null
+          render(cloned, container, isSVG)
+        }
+      }
+
+      // resolve in-DOM template if component did not provide render
+      // and no setup/mixin render functions are provided (by checking
+      // that the instance is still using the placeholder render fn)
+      if (hasNoRender && instance.render === emptyRender) {
+        // root directives check
+        if (__DEV__) {
+          for (let i = 0; i < container.attributes.length; i++) {
+            const attr = container.attributes[i]
+            if (attr.name !== 'v-cloak' && /^(v-|:|@)/.test(attr.name)) {
+              warnDeprecation(DeprecationTypes.DOM_TEMPLATE_MOUNT)
+              break
+            }
+          }
+        }
+        instance.render = null
+        ;(component as ComponentOptions).template = container.innerHTML
+        finishComponentSetup(instance, __NODE_JS__, true /* skip options */)
+      }
+
+      // clear content before mounting
+      container.innerHTML = ''
+
+      // TODO hydration
+      render(vnode, container, isSVG)
+
+      if (container instanceof Element) {
+        container.removeAttribute('v-cloak')
+        container.setAttribute('data-v-app', '')
+      }
+
+      isMounted = true
+      app._container = container
+      // for devtools and telemetry
+      ;(container as any).__vue_app__ = app
+      if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
+        devtoolsInitApp(app, version)
+      }
+
+      return instance.proxy!
+    }
+
+    instance.ctx._compat_destroy = app.unmount
+
+    return instance.proxy!
+  }
+}
index c2cc5c16ede4655741ad4f037675e48617abd1e1..7572c430d87a2d63eaaa45591557f20e4e66698e 100644 (file)
@@ -12,8 +12,7 @@ import {
   NOOP,
   extend,
   isString,
-  warnDeprecation,
-  DeprecationTypes
+  isFunction
 } from '@vue/shared'
 import {
   ReactiveEffect,
@@ -42,7 +41,7 @@ import { markAttrsAccessed } from './componentRenderUtils'
 import { currentRenderingInstance } from './componentRenderContext'
 import { warn } from './warning'
 import { UnionToIntersection } from './helpers/typeUtils'
-
+import { warnDeprecation, DeprecationTypes } from './compat/deprecations'
 /**
  * Custom properties added to component instances in any way and can be accessed through `this`
  *
@@ -356,7 +355,12 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
       ((globalProperties = appContext.config.globalProperties),
       hasOwn(globalProperties, key))
     ) {
-      return globalProperties[key]
+      if (__COMPAT__) {
+        const val = globalProperties[key]
+        return isFunction(val) ? val.bind(instance.proxy) : val
+      } else {
+        return globalProperties[key]
+      }
     } else if (
       __DEV__ &&
       currentRenderingInstance &&
@@ -510,7 +514,10 @@ export function createRenderContext(instance: ComponentInternalInstance) {
     Object.defineProperty(target, key, {
       configurable: true,
       enumerable: false,
-      get: () => globalProperties[key],
+      get: () => {
+        const val = globalProperties[key]
+        return __COMPAT__ && isFunction(val) ? val.bind(instance.proxy) : val
+      },
       set: NOOP
     })
   })
index 6026d4c248dcc46035f63d1d8f569c2badefa221..b0bc0645d0a37dc0df201e6bdbf8d4fe35b32e07 100644 (file)
@@ -279,3 +279,10 @@ const _ssrUtils = {
  * @internal
  */
 export const ssrUtils = (__NODE_JS__ ? _ssrUtils : null) as typeof _ssrUtils
+
+// 2.x COMPAT ------------------------------------------------------------------
+
+// Important: every function exported here must have `if (!__COMPAT__) return`
+// checks
+export { warnDeprecation, DeprecationTypes } from './compat/deprecations'
+export { createCompatVue, CompatVue } from './compat/global'
index 1a4265aa7e858af18580a19a37d5c010f3a8d93b..fe019a44353009d309fb489f6b90a4574da0e9a0 100644 (file)
@@ -8,20 +8,14 @@ import {
   HydrationRenderer,
   App,
   RootHydrateFunction,
-  isRuntimeOnly
+  isRuntimeOnly,
+  warnDeprecation,
+  DeprecationTypes
 } from '@vue/runtime-core'
 import { nodeOps } from './nodeOps'
 import { patchProp, forcePatchProp } from './patchProp'
 // Importing from the compiler, will be tree-shaken in prod
-import {
-  isFunction,
-  isString,
-  isHTMLTag,
-  isSVGTag,
-  extend,
-  warnDeprecation,
-  DeprecationTypes
-} from '@vue/shared'
+import { isFunction, isString, isHTMLTag, isSVGTag, extend } from '@vue/shared'
 
 declare module '@vue/reactivity' {
   export interface RefUnwrapBailTypes {
diff --git a/packages/shared/src/deprecations.ts b/packages/shared/src/deprecations.ts
deleted file mode 100644 (file)
index ff097f3..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-export const enum DeprecationTypes {
-  DOM_TEMPLATE_MOUNT,
-  $MOUNT,
-  $DESTROY
-}
-
-type DeprecationData = {
-  message: string
-  link?: string
-}
-
-const deprecations: Record<DeprecationTypes, DeprecationData> = {
-  [DeprecationTypes.DOM_TEMPLATE_MOUNT]: {
-    message:
-      `Vue detected directives on the mount container. ` +
-      `In Vue 3, the container is no longer considered part of the template ` +
-      `and will not be processed/replaced.`,
-    link: `https://v3.vuejs.org/guide/migration/mount-changes.html`
-  },
-
-  [DeprecationTypes.$MOUNT]: {
-    message:
-      `vm.$mount() has been deprecated. ` +
-      `Use createApp(RootComponent).mount() instead.`,
-    link: `https://v3.vuejs.org/guide/migration/global-api.html#mounting-app-instance`
-  },
-
-  [DeprecationTypes.$DESTROY]: {
-    message: `vm.$destroy() has been deprecated. Use app.unmount() instead.`,
-    link: `https://v3.vuejs.org/api/application-api.html#unmount`
-  }
-}
-
-export function warnDeprecation(key: DeprecationTypes) {
-  const { message, link } = deprecations[key]
-  console.warn(
-    `[Deprecation]: ${message}${link ? `\nFor more details, see ${link}` : ``}`
-  )
-}
index 8a16c7c4840ab239fd7d0a8b2ed4793dc61d6803..84b324beda3511e50f9e764a460e1b75fff0e30c 100644 (file)
@@ -12,7 +12,6 @@ export * from './domAttrConfig'
 export * from './escapeHtml'
 export * from './looseEqual'
 export * from './toDisplayString'
-export * from './deprecations'
 
 /**
  * List of @babel/parser plugins that are used for template expression
diff --git a/packages/vue-compat/src/apiGlobal.ts b/packages/vue-compat/src/apiGlobal.ts
deleted file mode 100644 (file)
index 1a9f95e..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-import { reactive } from '@vue/reactivity'
-import {
-  createApp,
-  defineComponent,
-  nextTick,
-  App,
-  AppConfig,
-  Plugin,
-  Component,
-  ComponentOptions,
-  ComponentPublicInstance,
-  Directive,
-  RenderFunction,
-  isRuntimeOnly
-} from '@vue/runtime-dom'
-import { extend } from '@vue/shared'
-
-// TODO make these getter/setters and trigger deprecation warnings
-export type LegacyConfig = AppConfig & {
-  /**
-   * @deprecated `config.silent` option has been removed
-   */
-  silent?: boolean
-  /**
-   * @deprecated use __VUE_PROD_DEVTOOLS__ compile-time feature flag instead
-   * https://github.com/vuejs/vue-next/tree/master/packages/vue#bundler-build-feature-flags
-   */
-  devtools?: boolean
-  /**
-   * @deprecated use `config.isCustomElement` instead
-   * https://v3.vuejs.org/guide/migration/global-api.html#config-ignoredelements-is-now-config-iscustomelement
-   */
-  ignoredElements?: (string | RegExp)[]
-  /**
-   * @deprecated
-   * https://v3.vuejs.org/guide/migration/keycode-modifiers.html
-   */
-  keyCodes?: Record<string, number | number[]>
-  /**
-   * @deprecated
-   * https://v3.vuejs.org/guide/migration/global-api.html#config-productiontip-removed
-   */
-  productionTip?: boolean
-}
-
-/**
- * @deprecated the default `Vue` export has been removed in Vue 3. The type for
- * the default export is provided only for migration purposes. Please use
- * named imports instead - e.g. `import { createApp } from 'vue'`.
- */
-export type GlobalVue = Pick<App, 'version' | 'component' | 'directive'> & {
-  // no inference here since these types are not meant for actual use - they
-  // are merely here to provide type checks for internal implementation and
-  // information for migration.
-  new (options?: ComponentOptions): ComponentPublicInstance
-
-  version: string
-  config: LegacyConfig
-
-  extend: typeof defineComponent
-  nextTick: typeof nextTick
-
-  use(plugin: Plugin, ...options: any[]): GlobalVue
-  mixin(mixin: ComponentOptions): GlobalVue
-
-  component(name: string): Component | undefined
-  component(name: string, component: Component): GlobalVue
-  directive(name: string): Directive | undefined
-  directive(name: string, directive: Directive): GlobalVue
-
-  compile(template: string): RenderFunction
-
-  /**
-   * @deprecated Vue 3 no longer needs set() for adding new properties.
-   */
-  set(target: any, key: string | number | symbol, value: any): void
-  /**
-   * @deprecated Vue 3 no longer needs delete() for property deletions.
-   */
-  delete(target: any, key: string | number | symbol): void
-  /**
-   * @deprecated use `reactive` instead.
-   */
-  observable: typeof reactive
-  /**
-   * @deprecated filters have been removed from Vue 3.
-   */
-  filter(name: string, arg: any): null
-}
-
-export const Vue: GlobalVue = function Vue(options: ComponentOptions = {}) {
-  const app = createApp(options)
-
-  // copy over global config mutations
-  for (const key in singletonApp.config) {
-    if (
-      key !== 'isNativeTag' &&
-      !(key === 'isCustomElement' && isRuntimeOnly())
-    ) {
-      // @ts-ignore
-      app.config[key] = singletonApp.config[key]
-    }
-  }
-
-  // TODO copy prototype augmentations as config.globalProperties
-
-  if (options.el) {
-    return app.mount(options.el)
-  } else {
-    return app._createRoot!(options)
-  }
-} as any
-
-const singletonApp = createApp({})
-
-Vue.version = __VERSION__
-Vue.config = singletonApp.config
-
-Vue.extend = ((baseOptions: ComponentOptions = {}) => {
-  return function ExtendedVueConstructor(inlineOptions?: ComponentOptions) {
-    if (!inlineOptions) {
-      return new Vue(baseOptions)
-    } else {
-      const mergedOptions = extend({}, baseOptions)
-      mergedOptions.mixins = [inlineOptions, ...(mergedOptions.mixins || [])]
-      return new Vue(mergedOptions)
-    }
-  }
-}) as any
-
-Vue.nextTick = nextTick
-
-Vue.set = (target, key, value) => {
-  // TODO deprecation warnings
-  target[key] = value
-}
-Vue.delete = (target, key) => {
-  // TODO deprecation warnings
-  delete target[key]
-}
-// TODO wrap with deprecation warning
-Vue.observable = reactive
-
-Vue.use = (p, ...options) => {
-  singletonApp.use(p, ...options)
-  return Vue
-}
-
-Vue.mixin = m => {
-  singletonApp.mixin(m)
-  return Vue
-}
-
-Vue.component = ((name: string, comp: any) => {
-  if (comp) {
-    singletonApp.component(name, comp)
-    return Vue
-  } else {
-    return singletonApp.component(name)
-  }
-}) as any
-
-Vue.directive = ((name: string, dir: any) => {
-  if (dir) {
-    singletonApp.directive(name, dir)
-    return Vue
-  } else {
-    return singletonApp.directive(name)
-  }
-}) as any
-
-Vue.filter = ((name: string, filter: any) => {
-  // TODO deprecation warning
-  // TODO compiler warning for filters (maybe behavior compat?)
-}) as any
index 481f3b5ff643f5f218fa5274b5df8d55e0cb53d8..a1aa615f64ce4fcd1cc2acc0adcec49f5956532c 100644 (file)
@@ -2,11 +2,15 @@
 // and the compiler, and supports on-the-fly compilation of the template option.
 import { initDev } from './dev'
 import { compile, CompilerOptions, CompilerError } from '@vue/compiler-dom'
-import { registerRuntimeCompiler, RenderFunction, warn } from '@vue/runtime-dom'
+import {
+  registerRuntimeCompiler,
+  RenderFunction,
+  warn,
+  createCompatVue
+} from '@vue/runtime-dom'
 import { isString, NOOP, generateCodeFrame, extend } from '@vue/shared'
 import { InternalRenderFunction } from 'packages/runtime-core/src/component'
 import * as runtimeDom from '@vue/runtime-dom'
-import { Vue } from './apiGlobal'
 
 if (__DEV__) {
   initDev()
@@ -87,6 +91,8 @@ function compileToFunction(
 
 registerRuntimeCompiler(compileToFunction)
 
+const Vue = createCompatVue()
+
 Vue.compile = compileToFunction
 extend(Vue, runtimeDom)