]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: class/style fallthrough compat
authorEvan You <yyx990803@gmail.com>
Thu, 22 Apr 2021 02:04:26 +0000 (22:04 -0400)
committerEvan You <yyx990803@gmail.com>
Thu, 22 Apr 2021 02:04:26 +0000 (22:04 -0400)
packages/runtime-core/src/compat/attrsFallthrough.ts [new file with mode: 0644]
packages/runtime-core/src/compat/compatConfig.ts
packages/runtime-core/src/compat/instance.ts
packages/runtime-core/src/componentProps.ts
packages/runtime-core/src/componentRenderUtils.ts

diff --git a/packages/runtime-core/src/compat/attrsFallthrough.ts b/packages/runtime-core/src/compat/attrsFallthrough.ts
new file mode 100644 (file)
index 0000000..56ffe16
--- /dev/null
@@ -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
+}
index 50f7efd698d6861ddc3f69c14dde1c889f9d8be8..40655111ca2712149b2dd7b1d6b73bf4771457e0 100644 (file)
@@ -216,15 +216,15 @@ const deprecationData: Record<DeprecationTypes, DeprecationData> = {
   },
 
   [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`
   },
 
index 8466d0cd6e8937a8723cca6bded0498472aa15a4..96525a68c634abbff7228819a6b79fc93a3be9c8 100644 (file)
@@ -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),
index 3321a39ddafaa010971ce37286c71d37aa22baeb..e7134746c022c8cb30913a7cf0218c05d33868c1 100644 (file)
@@ -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<P = Data> =
   | ComponentObjectPropsOptions<P>
@@ -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]) {
index 1274f474e635507a74e7c67249f22ee3c45679dd..ca215e54cef1466b26148f7aaf4d441787c349d1 100644 (file)
@@ -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)) {