})
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) {
.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()
}
`<div v-for="i in list">
<Comp v-slot="bar">foo</Comp>
</div>`,
- false,
)
assertDynamicSlots(
`<div v-for="i in list">
<Comp v-slot="bar">{{ i }}</Comp>
</div>`,
- true,
+ PatchFlags.DYNAMIC_SLOTS,
)
// reference the component's own slot variable should not force dynamic slots
`<Comp v-slot="foo">
<Comp v-slot="bar">{{ bar }}</Comp>
</Comp>`,
- false,
)
assertDynamicSlots(
`<Comp v-slot="foo">
<Comp v-slot="bar">{{ foo }}</Comp>
</Comp>`,
- true,
+ PatchFlags.DYNAMIC_SLOTS,
)
// #2564
`<div v-for="i in list">
<Comp v-slot="bar"><button @click="fn(i)" /></Comp>
</div>`,
- true,
+ PatchFlags.DYNAMIC_SLOTS,
)
assertDynamicSlots(
`<div v-for="i in list">
<Comp v-slot="bar"><button @click="fn()" /></Comp>
</div>`,
- false,
+ )
+
+ // #9380
+ assertDynamicSlots(
+ `<div v-for="i in list">
+ <Comp :i="i">foo</Comp>
+ </div>`,
+ PatchFlags.PROPS,
+ )
+
+ assertDynamicSlots(
+ `<div v-for="i in list">
+ <Comp v-slot="{ value = i }"><button @click="fn()" /></Comp>
+ </div>`,
+ PatchFlags.DYNAMIC_SLOTS,
+ )
+
+ assertDynamicSlots(
+ `<div v-for="i in list">
+ <Comp v-slot:[i]><button @click="fn()" /></Comp>
+ </div>`,
+ PatchFlags.DYNAMIC_SLOTS,
)
})
// 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.