diff --git a/packages/runtime-core/src/compat/deprecations.ts b/packages/runtime-core/src/compat/deprecations.ts index aec9391d..e416a7f4 100644 --- a/packages/runtime-core/src/compat/deprecations.ts +++ b/packages/runtime-core/src/compat/deprecations.ts @@ -25,6 +25,7 @@ export const enum DeprecationTypes { INSTANCE_CHILDREN = 'INSTANCE_CHILDREN', INSTANCE_LISTENERS = 'INSTANCE_LISTENERS', INSTANCE_SCOPED_SLOTS = 'INSTANCE_SCOPED_SLOTS', + INSTANCE_ATTRS_CLASS_STYLE = 'INSTANCE_ATTRS_CLASS_STYLE', OPTIONS_DATA_FN = 'OPTIONS_DATA_FN', OPTIONS_DATA_MERGE = 'OPTIONS_DATA_MERGE', @@ -188,6 +189,19 @@ const deprecationData: Record = { link: `https://v3.vuejs.org/guide/migration/slots-unification.html` }, + [DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE]: { + message: + `vm.$attrs now includes class and style bindings passed from parent. ` + + `Components with inheritAttrs: false will no longer auto-inherit ` + + `class/style on its root element. If your code relies on this behavior, ` + + `you may see broken styling and need to adjust your CSS. Otherwise, ` + + `you can suppress this warning with:` + + `\n\n configureCompat({ ${ + DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE + }: { warning: false }})\n`, + link: `https://v3.vuejs.org/guide/migration/attrs-includes-class-style.html` + }, + [DeprecationTypes.OPTIONS_DATA_FN]: { message: `The "data" option can no longer be a plain object. ` + diff --git a/packages/runtime-core/src/compat/instance.ts b/packages/runtime-core/src/compat/instance.ts index 88897e12..74792b05 100644 --- a/packages/runtime-core/src/compat/instance.ts +++ b/packages/runtime-core/src/compat/instance.ts @@ -2,9 +2,10 @@ import { extend, NOOP } from '@vue/shared' import { PublicPropertiesMap } from '../componentPublicInstance' import { getCompatChildren } from './instanceChildren' import { assertCompatEnabled } from './compatConfig' -import { DeprecationTypes } from './deprecations' +import { DeprecationTypes, warnDeprecation } from './deprecations' import { off, on, once } from './instanceEventEmitter' import { getCompatListeners } from './instanceListeners' +import { shallowReadonly } from '@vue/reactivity' export function installCompatInstanceProperties(map: PublicPropertiesMap) { const set = (target: any, key: any, val: any) => { @@ -40,7 +41,15 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) { $scopedSlots: i => { assertCompatEnabled(DeprecationTypes.INSTANCE_SCOPED_SLOTS) - return i.slots + return __DEV__ ? shallowReadonly(i.slots) : i.slots + }, + + // overrides existing accessor + $attrs: i => { + if (__DEV__ && i.type.inheritAttrs === false) { + warnDeprecation(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE) + } + return __DEV__ ? shallowReadonly(i.attrs) : i.attrs }, $on: i => on.bind(null, i),