Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(compiler-core/v-slot): force dynamic slots when slot referencing scope vars #9427

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
30 changes: 19 additions & 11 deletions packages/compiler-core/__tests__/transforms/vSlot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,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) {
Expand All @@ -493,8 +496,8 @@ describe('compiler: transform component slots', () => {
.children[0] as ComponentNode
flag = (innerComp.codegenNode as VNodeCall).patchFlag
}
if (shouldForce) {
expect(flag).toBe(genFlagText(PatchFlags.DYNAMIC_SLOTS))
if (expectedPatchFlag) {
expect(flag).toBe(genFlagText(expectedPatchFlag))
} else {
expect(flag).toBeUndefined()
}
Expand All @@ -503,45 +506,50 @@ describe('compiler: transform component slots', () => {
assertDynamicSlots(
`<div v-for="i in list">
<Comp v-slot="bar">foo</Comp>
</div>`,
false
</div>`
)

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
assertDynamicSlots(
`<Comp v-slot="foo">
<Comp v-slot="bar">{{ bar }}</Comp>
</Comp>`,
false
</Comp>`
)

assertDynamicSlots(
`<Comp v-slot="foo">
<Comp v-slot="bar">{{ foo }}</Comp>
</Comp>`,
true
PatchFlags.DYNAMIC_SLOTS
)

// #2564
assertDynamicSlots(
`<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>`
)

// #9380
assertDynamicSlots(
`<div v-for="i in list">
<Comp :i="i">foo</Comp>
</div>`,
false
PatchFlags.PROPS
)
})

Expand Down
6 changes: 4 additions & 2 deletions packages/compiler-core/src/transforms/vSlot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,11 @@ 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 only when the slot children actually uses the scope variables.
if (!__BROWSER__ && !context.ssr && context.prefixIdentifiers) {
hasDynamicSlots = hasScopeRef(node, context.identifiers)
hasDynamicSlots = children.some(child =>
hasScopeRef(child, context.identifiers)
)
edison1105 marked this conversation as resolved.
Show resolved Hide resolved
}

// 1. Check for slot with slotProps on component itself.
Expand Down