Skip to content

Commit 99d54b2

Browse files
authored
fix(compiler-core): force dynamic slots when slot referencing scope vars (#9427)
close #9380
1 parent 15fc75f commit 99d54b2

File tree

2 files changed

+41
-11
lines changed

2 files changed

+41
-11
lines changed

packages/compiler-core/__tests__/transforms/vSlot.spec.ts

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,10 @@ describe('compiler: transform component slots', () => {
478478
})
479479

480480
test('should only force dynamic slots when actually using scope vars w/ prefixIdentifiers: true', () => {
481-
function assertDynamicSlots(template: string, shouldForce: boolean) {
481+
function assertDynamicSlots(
482+
template: string,
483+
expectedPatchFlag?: PatchFlags,
484+
) {
482485
const { root } = parseWithSlots(template, { prefixIdentifiers: true })
483486
let flag: any
484487
if (root.children[0].type === NodeTypes.FOR) {
@@ -491,8 +494,8 @@ describe('compiler: transform component slots', () => {
491494
.children[0] as ComponentNode
492495
flag = (innerComp.codegenNode as VNodeCall).patchFlag
493496
}
494-
if (shouldForce) {
495-
expect(flag).toBe(PatchFlags.DYNAMIC_SLOTS)
497+
if (expectedPatchFlag) {
498+
expect(flag).toBe(expectedPatchFlag)
496499
} else {
497500
expect(flag).toBeUndefined()
498501
}
@@ -502,44 +505,63 @@ describe('compiler: transform component slots', () => {
502505
`<div v-for="i in list">
503506
<Comp v-slot="bar">foo</Comp>
504507
</div>`,
505-
false,
506508
)
507509

508510
assertDynamicSlots(
509511
`<div v-for="i in list">
510512
<Comp v-slot="bar">{{ i }}</Comp>
511513
</div>`,
512-
true,
514+
PatchFlags.DYNAMIC_SLOTS,
513515
)
514516

515517
// reference the component's own slot variable should not force dynamic slots
516518
assertDynamicSlots(
517519
`<Comp v-slot="foo">
518520
<Comp v-slot="bar">{{ bar }}</Comp>
519521
</Comp>`,
520-
false,
521522
)
522523

523524
assertDynamicSlots(
524525
`<Comp v-slot="foo">
525526
<Comp v-slot="bar">{{ foo }}</Comp>
526527
</Comp>`,
527-
true,
528+
PatchFlags.DYNAMIC_SLOTS,
528529
)
529530

530531
// #2564
531532
assertDynamicSlots(
532533
`<div v-for="i in list">
533534
<Comp v-slot="bar"><button @click="fn(i)" /></Comp>
534535
</div>`,
535-
true,
536+
PatchFlags.DYNAMIC_SLOTS,
536537
)
537538

538539
assertDynamicSlots(
539540
`<div v-for="i in list">
540541
<Comp v-slot="bar"><button @click="fn()" /></Comp>
541542
</div>`,
542-
false,
543+
)
544+
545+
// #9380
546+
assertDynamicSlots(
547+
`<div v-for="i in list">
548+
<Comp :i="i">foo</Comp>
549+
</div>`,
550+
PatchFlags.PROPS,
551+
)
552+
553+
assertDynamicSlots(
554+
`<div v-for="i in list">
555+
<Comp v-slot="{ value = i }"><button @click="fn()" /></Comp>
556+
</div>`,
557+
PatchFlags.DYNAMIC_SLOTS,
558+
)
559+
560+
assertDynamicSlots(
561+
`<div v-for="i in list">
562+
<Comp v-slot:[i]><button @click="fn()" /></Comp>
563+
</div>`,
564+
PatchFlags.DYNAMIC_SLOTS,
543565
)
544566
})
545567

packages/compiler-core/src/transforms/vSlot.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,17 @@ export function buildSlots(
131131
// since it likely uses a scope variable.
132132
let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0
133133
// with `prefixIdentifiers: true`, this can be further optimized to make
134-
// it dynamic only when the slot actually uses the scope variables.
134+
// it dynamic when
135+
// 1. the slot arg or exp uses the scope variables.
136+
// 2. the slot children use the scope variables.
135137
if (!__BROWSER__ && !context.ssr && context.prefixIdentifiers) {
136-
hasDynamicSlots = hasScopeRef(node, context.identifiers)
138+
hasDynamicSlots =
139+
node.props.some(
140+
prop =>
141+
isVSlot(prop) &&
142+
(hasScopeRef(prop.arg, context.identifiers) ||
143+
hasScopeRef(prop.exp, context.identifiers)),
144+
) || children.some(child => hasScopeRef(child, context.identifiers))
137145
}
138146

139147
// 1. Check for slot with slotProps on component itself.

0 commit comments

Comments
 (0)