From: Evan You Date: Thu, 22 Apr 2021 02:04:26 +0000 (-0400) Subject: wip: class/style fallthrough compat X-Git-Tag: v3.1.0-beta.1~59^2~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=12abd4af85234256933660d7ec826e69e6d5aedd;p=thirdparty%2Fvuejs%2Fcore.git wip: class/style fallthrough compat --- diff --git a/packages/runtime-core/src/compat/attrsFallthrough.ts b/packages/runtime-core/src/compat/attrsFallthrough.ts new file mode 100644 index 0000000000..56ffe16044 --- /dev/null +++ b/packages/runtime-core/src/compat/attrsFallthrough.ts @@ -0,0 +1,22 @@ +import { isOn } from '@vue/shared' +import { ComponentInternalInstance } from '../component' +import { DeprecationTypes, isCompatEnabled } from './compatConfig' + +export function shouldSkipAttr( + key: string, + instance: ComponentInternalInstance +): boolean { + if ( + (key === 'class' || key === 'style') && + isCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, instance) + ) { + return true + } + if ( + isOn(key) && + isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, instance) + ) { + return true + } + return false +} diff --git a/packages/runtime-core/src/compat/compatConfig.ts b/packages/runtime-core/src/compat/compatConfig.ts index 50f7efd698..40655111ca 100644 --- a/packages/runtime-core/src/compat/compatConfig.ts +++ b/packages/runtime-core/src/compat/compatConfig.ts @@ -216,15 +216,15 @@ const deprecationData: Record = { }, [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 disable the compat behavior and suppress this warning with:` + - `\n\n configureCompat({ ${ - DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE - }: false )\n`, + message: componentName => + `Component <${componentName}> has \`inheritAttrs: false\` but is ` + + `relying on class/style fallthrough from parent. In Vue 3, class/style ` + + `are now included in $attrs and will no longer fallthrough when ` + + `inheritAttrs is false. If you are already using v-bind="$attrs" on ` + + `component root it should render the same end result. ` + + `If you are binding $attrs to a non-root element and expecting ` + + `class/style to fallthrough on root, you will need to now manually bind ` + + `them on root via :class="$attrs.class".`, link: `https://v3.vuejs.org/guide/migration/attrs-includes-class-style.html` }, diff --git a/packages/runtime-core/src/compat/instance.ts b/packages/runtime-core/src/compat/instance.ts index 8466d0cd6e..96525a68c6 100644 --- a/packages/runtime-core/src/compat/instance.ts +++ b/packages/runtime-core/src/compat/instance.ts @@ -4,7 +4,6 @@ import { getCompatChildren } from './instanceChildren' import { DeprecationTypes, assertCompatEnabled, - checkCompatEnabled, isCompatEnabled } from './compatConfig' import { off, on, once } from './instanceEventEmitter' @@ -75,14 +74,6 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) { return __DEV__ ? shallowReadonly(i.slots) : i.slots }, - // overrides existing accessor - $attrs: i => { - if (__DEV__ && i.type.inheritAttrs === false) { - checkCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, i) - } - return __DEV__ ? shallowReadonly(i.attrs) : i.attrs - }, - $on: i => on.bind(null, i), $once: i => once.bind(null, i), $off: i => off.bind(null, i), diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 3321a39dda..e7134746c0 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -20,8 +20,7 @@ import { isReservedProp, EMPTY_ARR, def, - extend, - isOn + extend } from '@vue/shared' import { warn } from './warning' import { @@ -37,6 +36,7 @@ import { AppContext } from './apiCreateApp' import { createPropsDefaultThis } from './compat/props' import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig' import { DeprecationTypes } from './compat/compatConfig' +import { shouldSkipAttr } from './compat/attrsFallthrough' export type ComponentPropsOptions

= | ComponentObjectPropsOptions

@@ -229,11 +229,7 @@ export function updateProps( ) } } else { - if ( - __COMPAT__ && - isOn(key) && - isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, instance) - ) { + if (__COMPAT__ && shouldSkipAttr(key, instance)) { continue } if (value !== attrs[key]) { @@ -341,11 +337,7 @@ function setFullProps( // Any non-declared (either as a prop or an emitted event) props are put // into a separate `attrs` object for spreading. Make sure to preserve // original key casing - if ( - __COMPAT__ && - isOn(key) && - isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, instance) - ) { + if (__COMPAT__ && shouldSkipAttr(key, instance)) { continue } if (value !== attrs[key]) { diff --git a/packages/runtime-core/src/componentRenderUtils.ts b/packages/runtime-core/src/componentRenderUtils.ts index 1274f474e6..ca215e54ce 100644 --- a/packages/runtime-core/src/componentRenderUtils.ts +++ b/packages/runtime-core/src/componentRenderUtils.ts @@ -1,7 +1,8 @@ import { ComponentInternalInstance, FunctionalComponent, - Data + Data, + getComponentName } from './component' import { VNode, @@ -20,6 +21,11 @@ import { isHmrUpdating } from './hmr' import { NormalizedProps } from './componentProps' import { isEmitListener } from './componentEmits' import { setCurrentRenderingInstance } from './componentRenderContext' +import { + DeprecationTypes, + isCompatEnabled, + warnDeprecation +} from './compat/compatConfig' /** * dev only flag to track whether $attrs was used during render. @@ -117,7 +123,7 @@ export function renderComponentRoot( ;[root, setRoot] = getChildRoot(result) } - if (Component.inheritAttrs !== false && fallthroughAttrs) { + if (fallthroughAttrs && Component.inheritAttrs !== false) { const keys = Object.keys(fallthroughAttrs) const { shapeFlag } = root if (keys.length) { @@ -175,6 +181,29 @@ export function renderComponentRoot( } } + if ( + __COMPAT__ && + isCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, instance) && + vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT && + (root.shapeFlag & ShapeFlags.ELEMENT || + root.shapeFlag & ShapeFlags.COMPONENT) + ) { + const { class: cls, style } = vnode.props || {} + if (cls || style) { + if (__DEV__ && Component.inheritAttrs === false) { + warnDeprecation( + DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, + instance, + getComponentName(instance.type) + ) + } + root = cloneVNode(root, { + class: cls, + style: style + }) + } + } + // inherit directives if (vnode.dirs) { if (__DEV__ && !isElementRoot(root)) {