From: edison Date: Tue, 2 Sep 2025 09:24:56 +0000 (+0800) Subject: fix(compiler-core): force dynamic slots when slot referencing scope vars (#9427) X-Git-Tag: v3.5.21~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=99d54b28b46dbea006205dff71c383a31dd1b87a;p=thirdparty%2Fvuejs%2Fcore.git fix(compiler-core): force dynamic slots when slot referencing scope vars (#9427) close #9380 --- diff --git a/packages/compiler-core/__tests__/transforms/vSlot.spec.ts b/packages/compiler-core/__tests__/transforms/vSlot.spec.ts index e0f44a064..1213e218e 100644 --- a/packages/compiler-core/__tests__/transforms/vSlot.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vSlot.spec.ts @@ -478,7 +478,10 @@ describe('compiler: transform component slots', () => { }) test('should only force dynamic slots when actually using scope vars w/ prefixIdentifiers: true', () => { - function assertDynamicSlots(template: string, shouldForce: boolean) { + function assertDynamicSlots( + template: string, + expectedPatchFlag?: PatchFlags, + ) { const { root } = parseWithSlots(template, { prefixIdentifiers: true }) let flag: any if (root.children[0].type === NodeTypes.FOR) { @@ -491,8 +494,8 @@ describe('compiler: transform component slots', () => { .children[0] as ComponentNode flag = (innerComp.codegenNode as VNodeCall).patchFlag } - if (shouldForce) { - expect(flag).toBe(PatchFlags.DYNAMIC_SLOTS) + if (expectedPatchFlag) { + expect(flag).toBe(expectedPatchFlag) } else { expect(flag).toBeUndefined() } @@ -502,14 +505,13 @@ describe('compiler: transform component slots', () => { `
foo
`, - false, ) assertDynamicSlots( `
{{ i }}
`, - true, + PatchFlags.DYNAMIC_SLOTS, ) // reference the component's own slot variable should not force dynamic slots @@ -517,14 +519,13 @@ describe('compiler: transform component slots', () => { ` {{ bar }} `, - false, ) assertDynamicSlots( ` {{ foo }} `, - true, + PatchFlags.DYNAMIC_SLOTS, ) // #2564 @@ -532,14 +533,35 @@ describe('compiler: transform component slots', () => { `
`, - true, + PatchFlags.DYNAMIC_SLOTS, ) assertDynamicSlots( `
`, - false, + ) + + // #9380 + assertDynamicSlots( + `
+ foo +
`, + PatchFlags.PROPS, + ) + + assertDynamicSlots( + `
+
`, + PatchFlags.DYNAMIC_SLOTS, + ) + + assertDynamicSlots( + `
+
`, + PatchFlags.DYNAMIC_SLOTS, ) }) diff --git a/packages/compiler-core/src/transforms/vSlot.ts b/packages/compiler-core/src/transforms/vSlot.ts index 43296dcc9..4681791f8 100644 --- a/packages/compiler-core/src/transforms/vSlot.ts +++ b/packages/compiler-core/src/transforms/vSlot.ts @@ -131,9 +131,17 @@ export function buildSlots( // since it likely uses a scope variable. let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0 // with `prefixIdentifiers: true`, this can be further optimized to make - // it dynamic only when the slot actually uses the scope variables. + // it dynamic when + // 1. the slot arg or exp uses the scope variables. + // 2. the slot children use the scope variables. if (!__BROWSER__ && !context.ssr && context.prefixIdentifiers) { - hasDynamicSlots = hasScopeRef(node, context.identifiers) + hasDynamicSlots = + node.props.some( + prop => + isVSlot(prop) && + (hasScopeRef(prop.arg, context.identifiers) || + hasScopeRef(prop.exp, context.identifiers)), + ) || children.some(child => hasScopeRef(child, context.identifiers)) } // 1. Check for slot with slotProps on component itself.