]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core): fix resolving inheritAttrs from mixins (#3742)
authoredison <daiwei521@126.com>
Fri, 28 May 2021 01:53:41 +0000 (09:53 +0800)
committerGitHub <noreply@github.com>
Fri, 28 May 2021 01:53:41 +0000 (21:53 -0400)
fix #3741

packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/componentOptions.ts
packages/runtime-core/src/componentRenderUtils.ts
packages/server-renderer/src/render.ts

index 86425ca0141095058b93085662bbedbb1cc362ac..d358431d66b8b57ccd9b186de87ae09e6e4ca2d5 100644 (file)
@@ -301,6 +301,34 @@ describe('attribute fallthrough', () => {
     expect(root.innerHTML).toMatch(`<div>1</div>`)
   })
 
+  // #3741
+  it('should not fallthrough with inheritAttrs: false from mixins', () => {
+    const Parent = {
+      render() {
+        return h(Child, { foo: 1, class: 'parent' })
+      }
+    }
+
+    const mixin = {
+      inheritAttrs: false
+    }
+
+    const Child = defineComponent({
+      mixins: [mixin],
+      props: ['foo'],
+      render() {
+        return h('div', this.foo)
+      }
+    })
+
+    const root = document.createElement('div')
+    document.body.appendChild(root)
+    render(h(Parent), root)
+
+    // should not contain class
+    expect(root.innerHTML).toMatch(`<div>1</div>`)
+  })
+
   it('explicit spreading with inheritAttrs: false', () => {
     const Parent = {
       render() {
index aa92b3ed215069cab65c45ca466188046ce897ca..ec1aa65b380ebac1589f3428a2c2639c38251f52 100644 (file)
@@ -285,6 +285,12 @@ export interface ComponentInternalInstance {
    */
   emitsOptions: ObjectEmitsOptions | null
 
+  /**
+   * resolved inheritAttrs options
+   * @internal
+   */
+  inheritAttrs?: boolean
+
   // the rest are only for stateful components ---------------------------------
 
   // main proxy that serves as the public instance (`this`)
@@ -469,6 +475,9 @@ export function createComponentInstance(
     // props default value
     propsDefaults: EMPTY_OBJ,
 
+    // inheritAttrs
+    inheritAttrs: type.inheritAttrs,
+
     // state
     ctx: EMPTY_OBJ,
     data: EMPTY_OBJ,
index d281b3c51b1719901084cb196008b2a0e9213704..e467ecbc8689ba1a4b702770b346a3698ba7717b 100644 (file)
@@ -567,17 +567,14 @@ export function applyOptions(
     errorCaptured,
     serverPrefetch,
     // public API
-    expose
+    expose,
+    inheritAttrs
   } = options
 
   const publicThis = instance.proxy!
   const ctx = instance.ctx
   const globalMixins = instance.appContext.mixins
 
-  if (asMixin && render && instance.render === NOOP) {
-    instance.render = render as InternalRenderFunction
-  }
-
   // applyOptions is called non-as-mixin once per instance
   if (!asMixin) {
     shouldCacheAccess = false
@@ -755,17 +752,6 @@ export function applyOptions(
     })
   }
 
-  // asset options.
-  // To reduce memory usage, only components with mixins or extends will have
-  // resolved asset registry attached to instance.
-  if (asMixin) {
-    resolveInstanceAssets(instance, options, COMPONENTS)
-    resolveInstanceAssets(instance, options, DIRECTIVES)
-    if (__COMPAT__ && isCompatEnabled(DeprecationTypes.FILTERS, instance)) {
-      resolveInstanceAssets(instance, options, FILTERS)
-    }
-  }
-
   // lifecycle options
   if (!asMixin) {
     callSyncHook(
@@ -831,6 +817,27 @@ export function applyOptions(
       warn(`The \`expose\` option is ignored when used in mixins.`)
     }
   }
+
+  // options that are handled when creating the instance but also need to be
+  // applied from mixins
+  if (asMixin) {
+    if (render && instance.render === NOOP) {
+      instance.render = render as InternalRenderFunction
+    }
+
+    if (inheritAttrs != null && instance.type.inheritAttrs == null) {
+      instance.inheritAttrs = inheritAttrs
+    }
+
+    // asset options.
+    // To reduce memory usage, only components with mixins or extends will have
+    // resolved asset registry attached to instance.
+    resolveInstanceAssets(instance, options, COMPONENTS)
+    resolveInstanceAssets(instance, options, DIRECTIVES)
+    if (__COMPAT__ && isCompatEnabled(DeprecationTypes.FILTERS, instance)) {
+      resolveInstanceAssets(instance, options, FILTERS)
+    }
+  }
 }
 
 function resolveInstanceAssets(
index ca215e54cef1466b26148f7aaf4d441787c349d1..0563ba592ef058b465ac7e35c57d1bc507d21c9f 100644 (file)
@@ -55,7 +55,8 @@ export function renderComponentRoot(
     renderCache,
     data,
     setupState,
-    ctx
+    ctx,
+    inheritAttrs
   } = instance
 
   let result
@@ -123,7 +124,7 @@ export function renderComponentRoot(
       ;[root, setRoot] = getChildRoot(result)
     }
 
-    if (fallthroughAttrs && Component.inheritAttrs !== false) {
+    if (fallthroughAttrs && inheritAttrs !== false) {
       const keys = Object.keys(fallthroughAttrs)
       const { shapeFlag } = root
       if (keys.length) {
@@ -190,7 +191,7 @@ export function renderComponentRoot(
     ) {
       const { class: cls, style } = vnode.props || {}
       if (cls || style) {
-        if (__DEV__ && Component.inheritAttrs === false) {
+        if (__DEV__ && inheritAttrs === false) {
           warnDeprecation(
             DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE,
             instance,
index eaba85605e58dc782b4cd02d5a7d001d019f21a3..2b78dda03d92a04f3c1bea67db33463a4a7085cf 100644 (file)
@@ -132,8 +132,7 @@ function renderComponentSubTree(
     if (ssrRender) {
       // optimized
       // resolve fallthrough attrs
-      let attrs =
-        instance.type.inheritAttrs !== false ? instance.attrs : undefined
+      let attrs = instance.inheritAttrs !== false ? instance.attrs : undefined
       let hasCloned = false
 
       let cur = instance