diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 9498ced4..0a6670b2 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -33,6 +33,8 @@ import { } from './errorHandling' import { queuePostRenderEffect } from './renderer' import { warn } from './warning' +import { DeprecationTypes, warnDeprecation } from './compat/deprecations' +import { isCompatEnabled } from './compat/compatConfig' export type WatchEffect = (onInvalidate: InvalidateCbRegistrator) => void @@ -217,6 +219,21 @@ function doWatch( __DEV__ && warnInvalidSource(source) } + // 2.x array mutation watch compat + if (__COMPAT__ && cb && !deep) { + const baseGetter = getter + getter = () => { + const val = baseGetter() + if (isArray(val)) { + __DEV__ && warnDeprecation(DeprecationTypes.WATCH_ARRAY) + if (isCompatEnabled(DeprecationTypes.WATCH_ARRAY)) { + traverse(val) + } + } + return val + } + } + if (cb && deep) { const baseGetter = getter getter = () => traverse(baseGetter()) @@ -254,7 +271,14 @@ function doWatch( if (cb) { // watch(source, cb) const newValue = runner() - if (deep || forceTrigger || hasChanged(newValue, oldValue)) { + if ( + deep || + forceTrigger || + hasChanged(newValue, oldValue) || + (__COMPAT__ && + isArray(newValue) && + isCompatEnabled(DeprecationTypes.WATCH_ARRAY)) + ) { // cleanup before running cb again if (cleanup) { cleanup() diff --git a/packages/runtime-core/src/compat/compatConfig.ts b/packages/runtime-core/src/compat/compatConfig.ts index f6395883..c430509f 100644 --- a/packages/runtime-core/src/compat/compatConfig.ts +++ b/packages/runtime-core/src/compat/compatConfig.ts @@ -16,11 +16,16 @@ export function configureCompat(config: CompatConfig) { extend(globalCompatConfig, config) } -/** - * @internal - */ export function getCompatConfig( key: DeprecationTypes ): DeprecationConfigItem | undefined { return globalCompatConfig[key] } + +/** + * @internal + */ +export function isCompatEnabled(key: DeprecationTypes): boolean { + const config = getCompatConfig(key) + return !config || config.mode !== 3 +} diff --git a/packages/runtime-core/src/compat/deprecations.ts b/packages/runtime-core/src/compat/deprecations.ts index e345a0b2..62c3b906 100644 --- a/packages/runtime-core/src/compat/deprecations.ts +++ b/packages/runtime-core/src/compat/deprecations.ts @@ -28,11 +28,10 @@ export const enum DeprecationTypes { OPTIONS_BEFORE_DESTROY = 'OPTIONS_BEFORE_DESTROY', OPTIONS_DESTROYED = 'OPTIONS_DESTROYED', + V_ON_KEYCODE_MODIFIER = 'V_ON_KEYCODE_MODIFIER', PROPS_DEFAULT_THIS = 'PROPS_DEFAULT_THIS', - CUSTOM_DIR = 'CUSTOM_DIR', - - V_ON_KEYCODE_MODIFIER = 'V_ON_KEYCODE_MODIFIER' + WATCH_ARRAY = 'WATCH_ARRAY' } type DeprecationData = { @@ -181,6 +180,13 @@ const deprecationMessages: Record = { message: `\`destroyed\` has been renamed to \`unmounted\`.` }, + [DeprecationTypes.V_ON_KEYCODE_MODIFIER]: { + message: + `Using keyCode as v-on modifier is no longer supported. ` + + `Use kebab-case key name modifiers instead.`, + link: `https://v3.vuejs.org/guide/migration/keycode-modifiers.html` + }, + [DeprecationTypes.PROPS_DEFAULT_THIS]: { message: (key: string) => `props default value function no longer has access to "this". ` + @@ -195,11 +201,15 @@ const deprecationMessages: Record = { link: `https://v3.vuejs.org/guide/migration/custom-directives.html` }, - [DeprecationTypes.V_ON_KEYCODE_MODIFIER]: { + [DeprecationTypes.WATCH_ARRAY]: { message: - `Using keyCode as v-on modifier is no longer supported. ` + - `Use kebab-case key name modifiers instead.`, - link: `https://v3.vuejs.org/guide/migration/keycode-modifiers.html` + `"watch" option or vm.$watch on an array value will no longer ` + + `trigger on array mutation unless the "deep" option is specified. ` + + `If current usage is intended, you can suppress this warning with:` + + `\n\n configureCompat({ ${ + DeprecationTypes.WATCH_ARRAY + }: { mode: 3 }})\n`, + link: `https://v3.vuejs.org/guide/migration/watch.html` } } @@ -215,7 +225,10 @@ export function warnDeprecation(key: DeprecationTypes, ...args: any[]) { // check user config const config = getCompatConfig(key) - if (config && config.warning === false) { + if ( + config && + (config.warning === false || (config.mode === 3 && config.warning !== true)) + ) { return } diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 569b51ab..9f8a94cc 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -288,12 +288,12 @@ export { LegacyConfig } from './compat/globalConfig' import { warnDeprecation } from './compat/deprecations' import { createCompatVue } from './compat/global' -import { getCompatConfig } from './compat/compatConfig' +import { isCompatEnabled } from './compat/compatConfig' const _compatUtils = { warnDeprecation, createCompatVue, - getCompatConfig + isCompatEnabled } export const compatUtils = (__COMPAT__