} from './errorHandling'
import { queuePostRenderEffect } from './renderer'
import { warn } from './warning'
-import { DeprecationTypes, warnDeprecation } from './compat/deprecations'
-import { isCompatEnabled } from './compat/compatConfig'
+import { DeprecationTypes } from './compat/deprecations'
+import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
export type WatchEffect = (onInvalidate: InvalidateCbRegistrator) => void
const baseGetter = getter
getter = () => {
const val = baseGetter()
- if (isArray(val)) {
- __DEV__ && warnDeprecation(DeprecationTypes.WATCH_ARRAY)
- if (isCompatEnabled(DeprecationTypes.WATCH_ARRAY)) {
- traverse(val)
- }
+ if (
+ isArray(val) &&
+ softAssertCompatEnabled(DeprecationTypes.WATCH_ARRAY)
+ ) {
+ traverse(val)
}
return val
}
import { ComponentInternalInstance } from '../component'
import { ComponentPublicInstance } from '../componentPublicInstance'
import { VNode } from '../vnode'
-import { DeprecationTypes, warnDeprecation } from './deprecations'
+import { assertCompatEnabled } from './compatConfig'
+import { DeprecationTypes } from './deprecations'
export function getInstanceChildren(
instance: ComponentInternalInstance
): ComponentPublicInstance[] {
- __DEV__ && warnDeprecation(DeprecationTypes.INSTANCE_CHILDREN)
+ assertCompatEnabled(DeprecationTypes.INSTANCE_CHILDREN)
const root = instance.subTree
const children: ComponentPublicInstance[] = []
if (root) {
import { extend } from '@vue/shared'
-import { DeprecationTypes } from './deprecations'
+import { DeprecationTypes, warnDeprecation } from './deprecations'
export type CompatConfig = Partial<
Record<DeprecationTypes, DeprecationConfigItem>
>
export interface DeprecationConfigItem {
- warning?: boolean // defaults to true
- mode?: 2 | 3 // defaults to 2
+ warning?: boolean // default: true
+ enabled?: boolean // default: true
}
const globalCompatConfig: CompatConfig = {}
return globalCompatConfig[key]
}
-/**
- * @internal
- */
export function isCompatEnabled(key: DeprecationTypes): boolean {
const config = getCompatConfig(key)
- return !config || config.mode !== 3
+ return !config || config.enabled !== false
+}
+
+export function assertCompatEnabled(key: DeprecationTypes, ...args: any[]) {
+ if (!isCompatEnabled(key)) {
+ throw new Error(`${key} compat has been disabled.`)
+ } else if (__DEV__) {
+ warnDeprecation(key, ...args)
+ }
+}
+
+export function softAssertCompatEnabled(key: DeprecationTypes, ...args: any[]) {
+ if (__DEV__) {
+ warnDeprecation(key, ...args)
+ }
+ return isCompatEnabled(key)
}
import { isArray } from '@vue/shared'
import { ObjectDirective, DirectiveHook } from '../directives'
-import { DeprecationTypes, warnDeprecation } from './deprecations'
+import { softAssertCompatEnabled } from './compatConfig'
+import { DeprecationTypes } from './deprecations'
export interface LegacyDirective {
bind?: DirectiveHook
mappedName.forEach(name => {
const mappedHook = dir[name]
if (mappedHook) {
- __DEV__ &&
- warnDeprecation(DeprecationTypes.CUSTOM_DIR, mappedName, name)
+ softAssertCompatEnabled(DeprecationTypes.CUSTOM_DIR, mappedName, name)
hook.push(mappedHook)
}
})
return hook.length ? hook : undefined
} else {
- if (__DEV__ && dir[mappedName]) {
- warnDeprecation(DeprecationTypes.CUSTOM_DIR, mappedName, name)
+ if (dir[mappedName]) {
+ softAssertCompatEnabled(DeprecationTypes.CUSTOM_DIR, mappedName, name)
}
return dir[mappedName]
}
import { getCompatConfig } from './compatConfig'
export const enum DeprecationTypes {
+ GLOBAL_MOUNT = 'GLOBAL_MOUNT',
+ GLOBAL_MOUNT_CONTAINER = 'GLOBAL_MOUNT_CONTAINER',
+ GLOBAL_EXTEND = 'GLOBAL_EXTEND',
+ GLOBAL_PROTOTYPE = 'GLOBAL_PROTOTYPE',
+ GLOBAL_SET = 'GLOBAL_SET',
+ GLOBAL_DELETE = 'GLOBAL_DELETE',
+ GLOBAL_OBSERVABLE = 'GLOBAL_OBSERVABLE',
+
CONFIG_SILENT = 'CONFIG_SILENT',
CONFIG_DEVTOOLS = 'CONFIG_DEVTOOLS',
CONFIG_KEY_CODES = 'CONFIG_KEY_CODES',
CONFIG_PRODUCTION_TIP = 'CONFIG_PRODUCTION_TIP',
CONFIG_IGNORED_ELEMENTS = 'CONFIG_IGNORED_ELEMENTS',
- GLOBAL_PROTOTYPE = 'GLOBAL_PROTOTYPE',
- GLOBAL_SET = 'GLOBAL_SET',
- GLOBAL_DELETE = 'GLOBAL_DELETE',
- GLOBAL_OBSERVABLE = 'GLOBAL_OBSERVABLE',
- GLOBAL_MOUNT_CONTAINER = 'GLOBAL_MOUNT_CONTAINER',
-
INSTANCE_SET = 'INSTANCE_SET',
INSTANCE_DELETE = 'INSTANCE_DELETE',
- INSTANCE_MOUNT = 'INSTANCE_MOUNT',
INSTANCE_DESTROY = 'INSTANCE_DESTROY',
INSTANCE_EVENT_EMITTER = 'INSTANCE_EVENT_EMITTER',
INSTANCE_EVENT_HOOKS = 'INSTANCE_EVENT_HOOKS',
link?: string
}
-const deprecationMessages: Record<DeprecationTypes, DeprecationData> = {
+const deprecationData: Record<DeprecationTypes, DeprecationData> = {
+ [DeprecationTypes.GLOBAL_MOUNT]: {
+ message:
+ `The global app bootstrapping 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.GLOBAL_MOUNT_CONTAINER]: {
+ 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.GLOBAL_EXTEND]: {
+ message:
+ `Vue.extend() has been removed in Vue 3. ` +
+ `Use defineComponent() instead.`,
+ link: `https://v3.vuejs.org/api/global-api.html#definecomponent`
+ },
+
+ [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.CONFIG_SILENT]: {
message:
`config.silent has been removed because it is not good practice to ` +
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_MOUNT_CONTAINER]: {
- 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_MOUNT]: {
- message:
- `The global app bootstrapping 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`
const config = getCompatConfig(key)
if (
config &&
- (config.warning === false || (config.mode === 3 && config.warning !== true))
+ (config.warning === false ||
+ (config.enabled === false && config.warning !== true))
) {
return
}
}
hasWarned[dupKey] = true
- const { message, link } = deprecationMessages[key]
+ const { message, link } = deprecationData[key]
warn(
`(DEPRECATION ${key}) ${
typeof message === 'function' ? message(...args) : message
import { isArray } from '@vue/shared'
import { ComponentInternalInstance } from '../component'
import { callWithAsyncErrorHandling, ErrorCodes } from '../errorHandling'
-import { DeprecationTypes, warnDeprecation } from './deprecations'
+import { assertCompatEnabled } from './compatConfig'
+import { DeprecationTypes } from './deprecations'
interface EventRegistry {
[event: string]: Function[] | undefined
if (isArray(event)) {
event.forEach(e => on(instance, e, fn))
} else {
+ if (event.startsWith('hook:')) {
+ assertCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS)
+ } else {
+ assertCompatEnabled(DeprecationTypes.INSTANCE_EVENT_EMITTER)
+ }
const events = getRegistry(instance)
;(events[event] || (events[event] = [])).push(fn)
- if (__DEV__) {
- if (event.startsWith('hook:')) {
- warnDeprecation(DeprecationTypes.INSTANCE_EVENT_HOOKS)
- } else {
- warnDeprecation(DeprecationTypes.INSTANCE_EVENT_EMITTER)
- }
- }
}
return instance.proxy
}
event?: string,
fn?: Function
) {
- __DEV__ && warnDeprecation(DeprecationTypes.INSTANCE_EVENT_EMITTER)
+ assertCompatEnabled(DeprecationTypes.INSTANCE_EVENT_EMITTER)
const vm = instance.proxy
// all
if (!arguments.length) {
import { version } from '..'
import { LegacyConfig } from './globalConfig'
import { LegacyDirective } from './customDirective'
-import { configureCompat } from './compatConfig'
+import {
+ assertCompatEnabled,
+ configureCompat,
+ isCompatEnabled,
+ softAssertCompatEnabled
+} from './compatConfig'
/**
* @deprecated the default `Vue` export has been removed in Vue 3. The type for
const singletonApp = createApp({})
function createCompatApp(options: ComponentOptions = {}, Ctor: any) {
+ assertCompatEnabled(DeprecationTypes.GLOBAL_MOUNT)
+
const { data } = options
- if (data && !isFunction(data)) {
- __DEV__ && warnDeprecation(DeprecationTypes.OPTIONS_DATA_FN)
+ if (
+ data &&
+ !isFunction(data) &&
+ softAssertCompatEnabled(DeprecationTypes.OPTIONS_DATA_FN)
+ ) {
options.data = () => data
}
isCopyingConfig = false
// copy prototype augmentations as config.globalProperties
+ const isPrototypeEnabled = isCompatEnabled(
+ DeprecationTypes.GLOBAL_PROTOTYPE
+ )
let hasPrototypeAugmentations = false
for (const key in Ctor.prototype) {
if (key !== 'constructor') {
hasPrototypeAugmentations = true
}
- app.config.globalProperties[key] = Ctor.prototype[key]
+ if (isPrototypeEnabled) {
+ app.config.globalProperties[key] = Ctor.prototype[key]
+ }
}
- if (hasPrototypeAugmentations) {
- __DEV__ && warnDeprecation(DeprecationTypes.GLOBAL_PROTOTYPE)
+ if (__DEV__ && hasPrototypeAugmentations) {
+ warnDeprecation(DeprecationTypes.GLOBAL_PROTOTYPE)
}
const vm = app._createRoot!(options)
Vue.version = __VERSION__
Vue.config = singletonApp.config
+ Vue.nextTick = nextTick
Vue.extend = ((options: ComponentOptions = {}) => {
+ assertCompatEnabled(DeprecationTypes.GLOBAL_EXTEND)
+
function SubVue(inlineOptions?: ComponentOptions) {
if (!inlineOptions) {
return createCompatApp(options, SubVue)
return SubVue
}) as any
- Vue.nextTick = nextTick
-
Vue.set = (target, key, value) => {
- __DEV__ && warnDeprecation(DeprecationTypes.GLOBAL_SET)
+ assertCompatEnabled(DeprecationTypes.GLOBAL_SET)
target[key] = value
}
Vue.delete = (target, key) => {
- __DEV__ && warnDeprecation(DeprecationTypes.GLOBAL_DELETE)
+ assertCompatEnabled(DeprecationTypes.GLOBAL_DELETE)
delete target[key]
}
- Vue.observable = __DEV__
- ? (target: any) => {
- warnDeprecation(DeprecationTypes.GLOBAL_OBSERVABLE)
- return reactive(target)
- }
- : reactive
+ Vue.observable = (target: any) => {
+ assertCompatEnabled(DeprecationTypes.GLOBAL_OBSERVABLE)
+ return reactive(target)
+ }
Vue.use = (p, ...options) => {
singletonApp.use(p, ...options)
import { isArray, isString } from '@vue/shared'
import { AppConfig } from '../apiCreateApp'
import { isRuntimeOnly } from '../component'
+import { isCompatEnabled } from './compatConfig'
import { DeprecationTypes, warnDeprecation } from './deprecations'
import { isCopyingConfig } from './global'
val = newVal
// compat for runtime ignoredElements -> isCustomElement
- if (key === 'ignoredElements' && !isRuntimeOnly() && isArray(newVal)) {
+ if (
+ key === 'ignoredElements' &&
+ isCompatEnabled(DeprecationTypes.CONFIG_IGNORED_ELEMENTS) &&
+ !isRuntimeOnly() &&
+ isArray(newVal)
+ ) {
config.isCustomElement = tag => {
return newVal.some(
val => (isString(val) ? val === tag : val.test(tag))
import { extend, NOOP } from '@vue/shared'
import { PublicPropertiesMap } from '../componentPublicInstance'
import { getInstanceChildren } from './children'
-import { DeprecationTypes, warnDeprecation } from './deprecations'
+import { assertCompatEnabled } from './compatConfig'
+import { DeprecationTypes } from './deprecations'
import { off, on, once } from './eventEmitter'
export function installCompatInstanceProperties(map: PublicPropertiesMap) {
extend(map, {
$set: () => {
- __DEV__ && warnDeprecation(DeprecationTypes.INSTANCE_SET)
+ assertCompatEnabled(DeprecationTypes.INSTANCE_SET)
return set
},
$delete: () => {
- __DEV__ && warnDeprecation(DeprecationTypes.INSTANCE_DELETE)
+ assertCompatEnabled(DeprecationTypes.INSTANCE_DELETE)
return del
},
$mount: i => {
- __DEV__ && warnDeprecation(DeprecationTypes.INSTANCE_MOUNT)
+ assertCompatEnabled(DeprecationTypes.GLOBAL_MOUNT)
// root mount override from ./global.ts in installCompatMount
return i.ctx._compat_mount || NOOP
},
$destroy: i => {
- __DEV__ && warnDeprecation(DeprecationTypes.INSTANCE_DESTROY)
+ assertCompatEnabled(DeprecationTypes.INSTANCE_DESTROY)
// root destroy override from ./global.ts in installCompatMount
return i.ctx._compat_destroy || NOOP
},
import { callWithAsyncErrorHandling } from './errorHandling'
import { UnionToIntersection } from './helpers/typeUtils'
import { deepMergeData } from './compat/data'
-import { DeprecationTypes, warnDeprecation } from './compat/deprecations'
+import { DeprecationTypes } from './compat/deprecations'
+import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
/**
* Interface for declaring custom options.
}
if (__COMPAT__) {
- if (beforeDestroy) {
- __DEV__ && warnDeprecation(DeprecationTypes.OPTIONS_BEFORE_DESTROY)
+ if (
+ beforeDestroy &&
+ softAssertCompatEnabled(DeprecationTypes.OPTIONS_BEFORE_DESTROY)
+ ) {
onBeforeUnmount(beforeDestroy.bind(publicThis))
}
- if (destroyed) {
- __DEV__ && warnDeprecation(DeprecationTypes.OPTIONS_DESTROYED)
+ if (
+ destroyed &&
+ softAssertCompatEnabled(DeprecationTypes.OPTIONS_DESTROYED)
+ ) {
onUnmounted(destroyed.bind(publicThis))
}
}
instance.data = reactive(data)
} else {
// existing data: this is a mixin or extends.
- if (__COMPAT__) {
+ if (__COMPAT__ && isCompatEnabled(DeprecationTypes.OPTIONS_DATA_MERGE)) {
deepMergeData(instance.data, data)
} else {
extend(instance.data, data)
import { InternalObjectKey } from './vnode'
import { AppContext } from './apiCreateApp'
import { createPropsDefaultThis } from './compat/props'
+import { isCompatEnabled } from './compat/compatConfig'
+import { DeprecationTypes } from './compat/deprecations'
export type ComponentPropsOptions<P = Data> =
| ComponentObjectPropsOptions<P>
value = propsDefaults[key]
} else {
setCurrentInstance(instance)
- value = propsDefaults[key] =
- __COMPAT__ && __DEV__
- ? defaultValue.call(createPropsDefaultThis(key), props)
- : defaultValue(props)
+ value = propsDefaults[key] = defaultValue.call(
+ __COMPAT__ &&
+ __DEV__ &&
+ isCompatEnabled(DeprecationTypes.PROPS_DEFAULT_THIS)
+ ? createPropsDefaultThis(key)
+ : null,
+ props
+ )
setCurrentInstance(null)
}
} else {
} from './devtools'
import { initFeatureFlags } from './featureFlags'
import { isAsyncWrapper } from './apiAsyncComponent'
+import { isCompatEnabled } from './compat/compatConfig'
+import { DeprecationTypes } from './compat/deprecations'
+
+const isHookEventCompatEnabled =
+ __COMPAT__ && isCompatEnabled(DeprecationTypes.INSTANCE_EVENT_HOOKS)
export interface Renderer<HostElement = RendererElement> {
render: RootRenderFunction<HostElement>
if ((vnodeHook = props && props.onVnodeBeforeMount)) {
invokeVNodeHook(vnodeHook, parent, initialVNode)
}
- if (__COMPAT__) {
+ if (__COMPAT__ && isHookEventCompatEnabled) {
instance.emit('hook:beforeMount')
}
parentSuspense
)
}
- if (__COMPAT__) {
+ if (__COMPAT__ && isHookEventCompatEnabled) {
queuePostRenderEffect(
() => instance.emit('hook:mounted'),
parentSuspense
// since the hook may be injected by a child keep-alive
if (initialVNode.shapeFlag & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
instance.a && queuePostRenderEffect(instance.a, parentSuspense)
- if (__COMPAT__) {
+ if (__COMPAT__ && isHookEventCompatEnabled) {
queuePostRenderEffect(
() => instance.emit('hook:activated'),
parentSuspense
if ((vnodeHook = next.props && next.props.onVnodeBeforeUpdate)) {
invokeVNodeHook(vnodeHook, parent, next, vnode)
}
- if (__COMPAT__) {
+ if (__COMPAT__ && isHookEventCompatEnabled) {
instance.emit('hook:beforeUpdate')
}
parentSuspense
)
}
- if (__COMPAT__) {
+ if (__COMPAT__ && isHookEventCompatEnabled) {
queuePostRenderEffect(
() => instance.emit('hook:updated'),
parentSuspense
if (bum) {
invokeArrayFns(bum)
}
- if (__COMPAT__) {
+ if (__COMPAT__ && isHookEventCompatEnabled) {
instance.emit('hook:beforeDestroy')
}
if (um) {
queuePostRenderEffect(um, parentSuspense)
}
- if (__COMPAT__) {
+ if (__COMPAT__ && isHookEventCompatEnabled) {
queuePostRenderEffect(
() => instance.emit('hook:destroyed'),
parentSuspense
* @private
*/
export const withKeys = (fn: Function, modifiers: string[]) => {
- let keyCodes: LegacyConfig['keyCodes']
+ let globalKeyCodes: LegacyConfig['keyCodes']
if (__COMPAT__) {
- keyCodes = ((getCurrentInstance()!.appContext
- .config as any) as LegacyConfig).keyCodes
+ if (compatUtils.isCompatEnabled(DeprecationTypes.CONFIG_KEY_CODES)) {
+ globalKeyCodes = ((getCurrentInstance()!.appContext
+ .config as any) as LegacyConfig).keyCodes
+ }
if (__DEV__ && modifiers.some(m => /^\d+$/.test(m))) {
compatUtils.warnDeprecation(DeprecationTypes.V_ON_KEYCODE_MODIFIER)
}
if (__COMPAT__) {
const keyCode = String(event.keyCode)
- if (modifiers.some(mod => mod == keyCode)) {
+ if (
+ compatUtils.isCompatEnabled(DeprecationTypes.V_ON_KEYCODE_MODIFIER) &&
+ modifiers.some(mod => mod == keyCode)
+ ) {
return fn(event)
}
- if (keyCodes) {
+ if (globalKeyCodes) {
for (const mod of modifiers) {
- const codes = keyCodes[mod]
+ const codes = globalKeyCodes[mod]
if (codes) {
const matches = isArray(codes)
? codes.some(code => String(code) === keyCode)