Skip to content

Commit d6607c9

Browse files
authored
fix(runtime-core): fix resolving inheritAttrs from mixins (#3742)
fix #3741
1 parent 9b2e894 commit d6607c9

File tree

5 files changed

+65
-21
lines changed

5 files changed

+65
-21
lines changed

packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts

+28
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,34 @@ describe('attribute fallthrough', () => {
301301
expect(root.innerHTML).toMatch(`<div>1</div>`)
302302
})
303303

304+
// #3741
305+
it('should not fallthrough with inheritAttrs: false from mixins', () => {
306+
const Parent = {
307+
render() {
308+
return h(Child, { foo: 1, class: 'parent' })
309+
}
310+
}
311+
312+
const mixin = {
313+
inheritAttrs: false
314+
}
315+
316+
const Child = defineComponent({
317+
mixins: [mixin],
318+
props: ['foo'],
319+
render() {
320+
return h('div', this.foo)
321+
}
322+
})
323+
324+
const root = document.createElement('div')
325+
document.body.appendChild(root)
326+
render(h(Parent), root)
327+
328+
// should not contain class
329+
expect(root.innerHTML).toMatch(`<div>1</div>`)
330+
})
331+
304332
it('explicit spreading with inheritAttrs: false', () => {
305333
const Parent = {
306334
render() {

packages/runtime-core/src/component.ts

+9
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,12 @@ export interface ComponentInternalInstance {
285285
*/
286286
emitsOptions: ObjectEmitsOptions | null
287287

288+
/**
289+
* resolved inheritAttrs options
290+
* @internal
291+
*/
292+
inheritAttrs?: boolean
293+
288294
// the rest are only for stateful components ---------------------------------
289295

290296
// main proxy that serves as the public instance (`this`)
@@ -469,6 +475,9 @@ export function createComponentInstance(
469475
// props default value
470476
propsDefaults: EMPTY_OBJ,
471477

478+
// inheritAttrs
479+
inheritAttrs: type.inheritAttrs,
480+
472481
// state
473482
ctx: EMPTY_OBJ,
474483
data: EMPTY_OBJ,

packages/runtime-core/src/componentOptions.ts

+23-16
Original file line numberDiff line numberDiff line change
@@ -567,17 +567,14 @@ export function applyOptions(
567567
errorCaptured,
568568
serverPrefetch,
569569
// public API
570-
expose
570+
expose,
571+
inheritAttrs
571572
} = options
572573

573574
const publicThis = instance.proxy!
574575
const ctx = instance.ctx
575576
const globalMixins = instance.appContext.mixins
576577

577-
if (asMixin && render && instance.render === NOOP) {
578-
instance.render = render as InternalRenderFunction
579-
}
580-
581578
// applyOptions is called non-as-mixin once per instance
582579
if (!asMixin) {
583580
shouldCacheAccess = false
@@ -755,17 +752,6 @@ export function applyOptions(
755752
})
756753
}
757754

758-
// asset options.
759-
// To reduce memory usage, only components with mixins or extends will have
760-
// resolved asset registry attached to instance.
761-
if (asMixin) {
762-
resolveInstanceAssets(instance, options, COMPONENTS)
763-
resolveInstanceAssets(instance, options, DIRECTIVES)
764-
if (__COMPAT__ && isCompatEnabled(DeprecationTypes.FILTERS, instance)) {
765-
resolveInstanceAssets(instance, options, FILTERS)
766-
}
767-
}
768-
769755
// lifecycle options
770756
if (!asMixin) {
771757
callSyncHook(
@@ -831,6 +817,27 @@ export function applyOptions(
831817
warn(`The \`expose\` option is ignored when used in mixins.`)
832818
}
833819
}
820+
821+
// options that are handled when creating the instance but also need to be
822+
// applied from mixins
823+
if (asMixin) {
824+
if (render && instance.render === NOOP) {
825+
instance.render = render as InternalRenderFunction
826+
}
827+
828+
if (inheritAttrs != null && instance.type.inheritAttrs == null) {
829+
instance.inheritAttrs = inheritAttrs
830+
}
831+
832+
// asset options.
833+
// To reduce memory usage, only components with mixins or extends will have
834+
// resolved asset registry attached to instance.
835+
resolveInstanceAssets(instance, options, COMPONENTS)
836+
resolveInstanceAssets(instance, options, DIRECTIVES)
837+
if (__COMPAT__ && isCompatEnabled(DeprecationTypes.FILTERS, instance)) {
838+
resolveInstanceAssets(instance, options, FILTERS)
839+
}
840+
}
834841
}
835842

836843
function resolveInstanceAssets(

packages/runtime-core/src/componentRenderUtils.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ export function renderComponentRoot(
5555
renderCache,
5656
data,
5757
setupState,
58-
ctx
58+
ctx,
59+
inheritAttrs
5960
} = instance
6061

6162
let result
@@ -123,7 +124,7 @@ export function renderComponentRoot(
123124
;[root, setRoot] = getChildRoot(result)
124125
}
125126

126-
if (fallthroughAttrs && Component.inheritAttrs !== false) {
127+
if (fallthroughAttrs && inheritAttrs !== false) {
127128
const keys = Object.keys(fallthroughAttrs)
128129
const { shapeFlag } = root
129130
if (keys.length) {
@@ -190,7 +191,7 @@ export function renderComponentRoot(
190191
) {
191192
const { class: cls, style } = vnode.props || {}
192193
if (cls || style) {
193-
if (__DEV__ && Component.inheritAttrs === false) {
194+
if (__DEV__ && inheritAttrs === false) {
194195
warnDeprecation(
195196
DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE,
196197
instance,

packages/server-renderer/src/render.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,7 @@ function renderComponentSubTree(
132132
if (ssrRender) {
133133
// optimized
134134
// resolve fallthrough attrs
135-
let attrs =
136-
instance.type.inheritAttrs !== false ? instance.attrs : undefined
135+
let attrs = instance.inheritAttrs !== false ? instance.attrs : undefined
137136
let hasCloned = false
138137

139138
let cur = instance

0 commit comments

Comments
 (0)