import { devtoolsInitApp, devtoolsUnmountApp } from './devtools'
import { isFunction, NO, isObject } from '@vue/shared'
import { version } from '.'
-import { installCompatMount } from './compat/globalMount'
-import { installLegacyConfigTraps } from './compat/globalConfig'
+import { installCompatMount, installLegacyConfigTraps } from './compat/global'
export interface App<HostElement = any> {
version: string
if (__COMPAT__) {
installCompatMount(app, context, render, hydrate)
- installLegacyConfigTraps(app.config)
+ if (__DEV__) installLegacyConfigTraps(app.config)
}
return app
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
+ CONFIG_IGNORED_ELEMENTS,
+
+ GLOBAL_PROTOTYPE,
+ GLOBAL_SET,
+ GLOBAL_DELETE,
+ GLOBAL_OBSERVABLE,
+ GLOBAL_DOM_TEMPLATE_MOUNT,
+
+ INSTANCE_SET,
+ INSTANCE_DELETE,
+ INSTANCE_MOUNT,
+ INSTANCE_DESTROY
}
type DeprecationData = {
}
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 ` +
return msg
},
link: `https://v3.vuejs.org/guide/migration/global-api.html#config-ignoredelements-is-now-config-iscustomelement`
+ },
+
+ [DeprecationTypes.GLOBAL_PROTOTYPE]: {
+ message:
+ `Vue.prototype is no longer available in Vue 3. ` +
+ `Use config.globalProperties instead.`,
+ link: `https://v3.vuejs.org/guide/migration/global-api.html#vue-prototype-replaced-by-config-globalproperties`
+ },
+
+ [DeprecationTypes.GLOBAL_SET]: {
+ message:
+ `Vue.set() has been removed as it is no longer needed in Vue 3. ` +
+ `Simply use native JavaScript mutations.`
+ },
+
+ [DeprecationTypes.GLOBAL_DELETE]: {
+ message:
+ `Vue.delete() has been removed as it is no longer needed in Vue 3. ` +
+ `Simply use native JavaScript mutations.`
+ },
+
+ [DeprecationTypes.GLOBAL_OBSERVABLE]: {
+ message:
+ `Vue.observable() has been removed. ` +
+ `Use \`import { reactive } from "vue"\` from Composition API instead.`,
+ link: `https://v3.vuejs.org/api/basic-reactivity.html`
+ },
+
+ [DeprecationTypes.GLOBAL_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.INSTANCE_SET]: {
+ message:
+ `vm.$set() has been removed as it is no longer needed in Vue 3. ` +
+ `Simply use native JavaScript mutations.`
+ },
+
+ [DeprecationTypes.INSTANCE_DELETE]: {
+ message:
+ `vm.$delete() has been removed as it is no longer needed in Vue 3. ` +
+ `Simply use native JavaScript mutations.`
+ },
+
+ [DeprecationTypes.INSTANCE_MOUNT]: {
+ message:
+ `The global app boostrapping API has changed: vm.$mount() and the "el" ` +
+ `option have been removed. Use createApp(RootComponent).mount() instead.`,
+ link: `https://v3.vuejs.org/guide/migration/global-api.html#mounting-app-instance`
+ },
+
+ [DeprecationTypes.INSTANCE_DESTROY]: {
+ message: `vm.$destroy() has been removed. Use app.unmount() instead.`,
+ link: `https://v3.vuejs.org/api/application-api.html#unmount`
}
}
import { reactive } from '@vue/reactivity'
-import { extend } from '@vue/shared'
-import { createApp } from '../../../runtime-dom/src'
-import { App, AppConfig, Plugin } from '../apiCreateApp'
+import { isFunction } from '@vue/shared'
+import { warn } from '../warning'
+import { cloneVNode, createVNode } from '../vnode'
+import { RootRenderFunction } from '../renderer'
+import { RootHydrateFunction } from '../hydration'
+import {
+ App,
+ AppConfig,
+ AppContext,
+ CreateAppFunction,
+ Plugin
+} from '../apiCreateApp'
import { defineComponent } from '../apiDefineComponent'
-import { Component, ComponentOptions, isRuntimeOnly } from '../component'
+import {
+ Component,
+ ComponentOptions,
+ createComponentInstance,
+ finishComponentSetup,
+ isRuntimeOnly,
+ setupComponent
+} from '../component'
import { RenderFunction } from '../componentOptions'
import { ComponentPublicInstance } from '../componentPublicInstance'
+import { devtoolsInitApp } from '../devtools'
import { Directive } from '../directives'
import { nextTick } from '../scheduler'
+import { warnDeprecation, DeprecationTypes } from './deprecations'
+import { version } from '..'
/**
* @deprecated the default `Vue` export has been removed in Vue 3. The type for
new (options?: ComponentOptions): ComponentPublicInstance
version: string
- config: AppConfig
+ config: AppConfig & LegacyConfig
extend: typeof defineComponent
nextTick: typeof nextTick
filter(name: string, arg: any): null
}
+// 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 let isCopyingConfig = false
// Legacy global Vue constructor
-export function createCompatVue(): CompatVue {
+export function createCompatVue(
+ createApp: CreateAppFunction<Element>
+): CompatVue {
if (!__COMPAT__) {
// @ts-ignore this function will never be called in non-compat mode
return
isCopyingConfig = false
// copy prototype augmentations as config.globalProperties
+ let hasPrototypeAugmentations = false
for (const key in Ctor.prototype) {
+ if (key !== 'constructor') {
+ hasPrototypeAugmentations = true
+ }
app.config.globalProperties[key] = Ctor.prototype[key]
}
+ if (hasPrototypeAugmentations) {
+ __DEV__ && warnDeprecation(DeprecationTypes.GLOBAL_PROTOTYPE)
+ }
const vm = app._createRoot!(options)
if (options.el) {
Vue.nextTick = nextTick
Vue.set = (target, key, value) => {
- // TODO deprecation warnings
+ __DEV__ && warnDeprecation(DeprecationTypes.GLOBAL_SET)
target[key] = value
}
+
Vue.delete = (target, key) => {
- // TODO deprecation warnings
+ __DEV__ && warnDeprecation(DeprecationTypes.GLOBAL_DELETE)
delete target[key]
}
- // TODO wrap with deprecation warning
- Vue.observable = reactive
+
+ Vue.observable = __DEV__
+ ? (target: any) => {
+ warnDeprecation(DeprecationTypes.GLOBAL_OBSERVABLE)
+ return reactive(target)
+ }
+ : reactive
Vue.use = (p, ...options) => {
singletonApp.use(p, ...options)
return Vue
}
+
+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.GLOBAL_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!
+ }
+}
+
+// dev only
+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
+ }
+ })
+ })
+}
+++ /dev/null
-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
- }
- })
- })
-}
+++ /dev/null
-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!
- }
-}
--- /dev/null
+import { extend, NOOP } from '@vue/shared'
+import { PublicPropertiesMap } from '../componentPublicInstance'
+import { DeprecationTypes, warnDeprecation } from './deprecations'
+
+export function installCompatInstanceProperties(map: PublicPropertiesMap) {
+ const set = (target: any, key: any, val: any) => {
+ target[key] = val
+ }
+
+ const del = (target: any, key: any) => {
+ delete target[key]
+ }
+
+ extend(map, {
+ $set: () => {
+ __DEV__ && warnDeprecation(DeprecationTypes.INSTANCE_SET)
+ return set
+ },
+ $delete: () => {
+ __DEV__ && warnDeprecation(DeprecationTypes.INSTANCE_DELETE)
+ return del
+ },
+ $mount: i => {
+ __DEV__ && warnDeprecation(DeprecationTypes.INSTANCE_MOUNT)
+ // root mount override from ./global.ts in installCompatMount
+ return i.ctx._compat_mount || NOOP
+ },
+ $destroy: i => {
+ __DEV__ && warnDeprecation(DeprecationTypes.INSTANCE_DESTROY)
+ // root destroy override from ./global.ts in installCompatMount
+ return i.ctx._compat_destroy || NOOP
+ }
+ } as PublicPropertiesMap)
+}
import { currentRenderingInstance } from './componentRenderContext'
import { warn } from './warning'
import { UnionToIntersection } from './helpers/typeUtils'
-import { warnDeprecation, DeprecationTypes } from './compat/deprecations'
+import { installCompatInstanceProperties } from './compat/instance'
+
/**
* Custom properties added to component instances in any way and can be accessed through `this`
*
M &
ComponentCustomProperties
-type PublicPropertiesMap = Record<string, (i: ComponentInternalInstance) => any>
+export type PublicPropertiesMap = Record<
+ string,
+ (i: ComponentInternalInstance) => any
+>
/**
* #2437 In Vue 3, functional components do not have a public instance proxy but
} as PublicPropertiesMap)
if (__COMPAT__) {
- extend(publicPropertiesMap, {
- $mount: i => {
- if (__DEV__) {
- warnDeprecation(DeprecationTypes.$MOUNT)
- }
- // root mount override from apiCreateApp.ts
- return i.ctx._compat_mount || NOOP
- },
- $destroy: i => {
- if (__DEV__) {
- warnDeprecation(DeprecationTypes.$DESTROY)
- }
- // root destroy override from apiCreateApp.ts
- return i.ctx._compat_destroy || NOOP
- }
- } as PublicPropertiesMap)
+ installCompatInstanceProperties(publicPropertiesMap)
}
const enum AccessTypes {
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)
+ warnDeprecation(DeprecationTypes.GLOBAL_DOM_TEMPLATE_MOUNT)
break
}
}
registerRuntimeCompiler,
RenderFunction,
warn,
+ createApp,
createCompatVue
} from '@vue/runtime-dom'
import { isString, NOOP, generateCodeFrame, extend } from '@vue/shared'
registerRuntimeCompiler(compileToFunction)
-const Vue = createCompatVue()
+const Vue = createCompatVue(createApp)
Vue.compile = compileToFunction
extend(Vue, runtimeDom)