From 0106d98ccd3fdd4c1e6e6930f9b53c30b98fe057 Mon Sep 17 00:00:00 2001 From: daiwei Date: Sat, 8 May 2021 09:40:21 +0800 Subject: [PATCH 1/4] fix(runtime-core): fix resolving inheritAttrs from mixins --- packages/runtime-core/src/componentOptions.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 366ac379dcf..7383d0d8abe 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -556,7 +556,8 @@ export function applyOptions( renderTriggered, errorCaptured, // public API - expose + expose, + inheritAttrs } = options const publicThis = instance.proxy! @@ -748,6 +749,7 @@ export function applyOptions( // To reduce memory usage, only components with mixins or extends will have // resolved asset registry attached to instance. if (asMixin) { + if (inheritAttrs !== undefined) instance.type.inheritAttrs = inheritAttrs resolveInstanceAssets(instance, options, COMPONENTS) resolveInstanceAssets(instance, options, DIRECTIVES) if (__COMPAT__ && isCompatEnabled(DeprecationTypes.FILTERS, instance)) { From b0ce9433f11059467de70cbee8564d432f34f21b Mon Sep 17 00:00:00 2001 From: daiwei Date: Mon, 10 May 2021 08:53:32 +0800 Subject: [PATCH 2/4] test: add test case --- .../rendererAttrsFallthrough.spec.ts | 28 +++++++++++++++++++ packages/runtime-core/src/componentOptions.ts | 3 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts b/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts index 86425ca0141..d358431d66b 100644 --- a/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts +++ b/packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts @@ -301,6 +301,34 @@ describe('attribute fallthrough', () => { expect(root.innerHTML).toMatch(`
1
`) }) + // #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(`
1
`) + }) + it('explicit spreading with inheritAttrs: false', () => { const Parent = { render() { diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 7383d0d8abe..5ca1ffd8093 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -749,12 +749,13 @@ export function applyOptions( // To reduce memory usage, only components with mixins or extends will have // resolved asset registry attached to instance. if (asMixin) { - if (inheritAttrs !== undefined) instance.type.inheritAttrs = inheritAttrs resolveInstanceAssets(instance, options, COMPONENTS) resolveInstanceAssets(instance, options, DIRECTIVES) if (__COMPAT__ && isCompatEnabled(DeprecationTypes.FILTERS, instance)) { resolveInstanceAssets(instance, options, FILTERS) } + + if (inheritAttrs !== undefined) instance.type.inheritAttrs = inheritAttrs } // lifecycle options From 1243c977a5171da64aea0a6e549b6d503cf2d93e Mon Sep 17 00:00:00 2001 From: daiwei Date: Thu, 13 May 2021 09:06:22 +0800 Subject: [PATCH 3/4] chore: change solution chore: improve code chore: improve code --- packages/runtime-core/src/component.ts | 9 +++++++++ packages/runtime-core/src/componentOptions.ts | 2 +- packages/runtime-core/src/componentRenderUtils.ts | 7 ++++--- packages/server-renderer/src/render.ts | 3 +-- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 54cf487bb45..0c271984dbe 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -284,6 +284,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`) @@ -464,6 +470,9 @@ export function createComponentInstance( // props default value propsDefaults: EMPTY_OBJ, + // inheritAttrs + inheritAttrs: type.inheritAttrs, + // state ctx: EMPTY_OBJ, data: EMPTY_OBJ, diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 5ca1ffd8093..a0c98ae1558 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -755,7 +755,7 @@ export function applyOptions( resolveInstanceAssets(instance, options, FILTERS) } - if (inheritAttrs !== undefined) instance.type.inheritAttrs = inheritAttrs + if (inheritAttrs !== undefined) instance.inheritAttrs = inheritAttrs } // lifecycle options diff --git a/packages/runtime-core/src/componentRenderUtils.ts b/packages/runtime-core/src/componentRenderUtils.ts index ca215e54cef..0563ba592ef 100644 --- a/packages/runtime-core/src/componentRenderUtils.ts +++ b/packages/runtime-core/src/componentRenderUtils.ts @@ -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, diff --git a/packages/server-renderer/src/render.ts b/packages/server-renderer/src/render.ts index f820fa305af..801b3e20e3f 100644 --- a/packages/server-renderer/src/render.ts +++ b/packages/server-renderer/src/render.ts @@ -128,8 +128,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 From 072b35fd5196c16d1724b5b345abb7bb4564cdf9 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 27 May 2021 21:44:17 -0400 Subject: [PATCH 4/4] fix: only set inheritAttrs from mixin if component self does not have the option --- packages/runtime-core/src/componentOptions.ts | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index a0c98ae1558..2ce21470590 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -564,10 +564,6 @@ export function applyOptions( 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 @@ -745,19 +741,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) - } - - if (inheritAttrs !== undefined) instance.inheritAttrs = inheritAttrs - } - // lifecycle options if (!asMixin) { callSyncHook( @@ -831,6 +814,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(