Skip to content

Commit 61299d6

Browse files
committed
fix(compiler-core): properly track scope vars in v-for + slot
chore: improve code chore: improve code chore: improve code
1 parent e3bc21f commit 61299d6

File tree

4 files changed

+29
-12
lines changed

4 files changed

+29
-12
lines changed

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

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,11 +100,12 @@ export const trackVForSlotScopes: NodeTransform = (node, context) => {
100100

101101
export type SlotFnBuilder = (
102102
slotProps: ExpressionNode | undefined,
103+
vForProps: ExpressionNode | undefined,
103104
slotChildren: TemplateChildNode[],
104105
loc: SourceLocation
105106
) => FunctionExpression
106107

107-
const buildClientSlotFn: SlotFnBuilder = (props, children, loc) =>
108+
const buildClientSlotFn: SlotFnBuilder = (props, _vFor, children, loc) =>
108109
createFunctionExpression(
109110
props,
110111
children,
@@ -138,6 +139,9 @@ export function buildSlots(
138139
hasDynamicSlots = hasScopeRef(node, context.identifiers)
139140
}
140141

142+
let vFor: DirectiveNode | undefined
143+
let vForProps: ExpressionNode | undefined
144+
141145
// 1. Check for slot with slotProps on component itself.
142146
// <Comp v-slot="{ prop }"/>
143147
const onComponentSlot = findDir(node, 'slot', true)
@@ -146,10 +150,12 @@ export function buildSlots(
146150
if (arg && !isStaticExp(arg)) {
147151
hasDynamicSlots = true
148152
}
153+
vFor = findDir(node, 'for')
154+
if (vFor) vForProps = vFor.exp
149155
slotsProperties.push(
150156
createObjectProperty(
151157
arg || createSimpleExpression('default', true),
152-
buildSlotFn(exp, children, loc)
158+
buildSlotFn(exp, vForProps, children, loc)
153159
)
154160
)
155161
}
@@ -201,11 +207,13 @@ export function buildSlots(
201207
hasDynamicSlots = true
202208
}
203209

204-
const slotFunction = buildSlotFn(slotProps, slotChildren, slotLoc)
210+
vFor = findDir(slotElement, 'for')
211+
if (vFor) vForProps = vFor.exp
212+
const slotFunction = buildSlotFn(slotProps, vForProps, slotChildren, slotLoc)
213+
205214
// check if this slot is conditional (v-if/v-for)
206215
let vIf: DirectiveNode | undefined
207216
let vElse: DirectiveNode | undefined
208-
let vFor: DirectiveNode | undefined
209217
if ((vIf = findDir(slotElement, 'if'))) {
210218
hasDynamicSlots = true
211219
dynamicSlots.push(
@@ -257,7 +265,7 @@ export function buildSlots(
257265
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, vElse.loc)
258266
)
259267
}
260-
} else if ((vFor = findDir(slotElement, 'for'))) {
268+
} else if (vFor) {
261269
hasDynamicSlots = true
262270
const parseResult =
263271
vFor.parseResult ||
@@ -306,7 +314,7 @@ export function buildSlots(
306314
props: ExpressionNode | undefined,
307315
children: TemplateChildNode[]
308316
) => {
309-
const fn = buildSlotFn(props, children, loc)
317+
const fn = buildSlotFn(props, undefined, children, loc)
310318
if (__COMPAT__ && context.compatConfig) {
311319
fn.isNonScopedSlot = true
312320
}

packages/compiler-ssr/__tests__/ssrComponent.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ describe('ssr: components', () => {
201201
_push(\`\${_ssrInterpolate(msg + key + _ctx.bar)}\`)
202202
} else {
203203
return [
204-
_createTextVNode(_toDisplayString(msg + _ctx.key + _ctx.bar), 1 /* TEXT */)
204+
_createTextVNode(_toDisplayString(msg + key + _ctx.bar), 1 /* TEXT */)
205205
]
206206
}
207207
})

packages/compiler-ssr/src/transforms/ssrTransformComponent.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ export const ssrTransformComponent: NodeTransform = (node, context) => {
120120
// fallback in case the child is render-fn based). Store them in an array
121121
// for later use.
122122
if (clonedNode.children.length) {
123-
buildSlots(clonedNode, context, (props, children) => {
124-
vnodeBranches.push(createVNodeSlotBranch(props, children, context))
123+
buildSlots(clonedNode, context, (props, vFor, children) => {
124+
vnodeBranches.push(createVNodeSlotBranch(props, vFor, children, context))
125125
return createFunctionExpression(undefined)
126126
})
127127
}
@@ -145,7 +145,7 @@ export const ssrTransformComponent: NodeTransform = (node, context) => {
145145
const wipEntries: WIPSlotEntry[] = []
146146
wipMap.set(node, wipEntries)
147147

148-
const buildSSRSlotFn: SlotFnBuilder = (props, children, loc) => {
148+
const buildSSRSlotFn: SlotFnBuilder = (props, _vFor, children, loc) => {
149149
const param0 = (props && stringifyExpression(props)) || `_`
150150
const fn = createFunctionExpression(
151151
[param0, `_push`, `_parent`, `_scopeId`],
@@ -273,6 +273,7 @@ const vnodeDirectiveTransforms = {
273273

274274
function createVNodeSlotBranch(
275275
props: ExpressionNode | undefined,
276+
vFor: ExpressionNode | undefined,
276277
children: TemplateChildNode[],
277278
parentContext: TransformContext
278279
): ReturnStatement {
@@ -299,7 +300,7 @@ function createVNodeSlotBranch(
299300
tag: 'template',
300301
tagType: ElementTypes.TEMPLATE,
301302
isSelfClosing: false,
302-
// important: provide v-slot="props" on the wrapper for proper
303+
// important: provide v-slot="props" and v-for="exp" on the wrapper for proper
303304
// scope analysis
304305
props: [
305306
{
@@ -309,6 +310,14 @@ function createVNodeSlotBranch(
309310
arg: undefined,
310311
modifiers: [],
311312
loc: locStub
313+
},
314+
{
315+
type: NodeTypes.DIRECTIVE,
316+
name: 'for',
317+
exp: vFor,
318+
arg: undefined,
319+
modifiers: [],
320+
loc: locStub
312321
}
313322
],
314323
children,

packages/compiler-ssr/src/transforms/ssrTransformSuspense.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export function ssrTransformSuspense(
3636
wipSlots: []
3737
}
3838
wipMap.set(node, wipEntry)
39-
wipEntry.slotsExp = buildSlots(node, context, (_props, children, loc) => {
39+
wipEntry.slotsExp = buildSlots(node, context, (_props, _vFor, children, loc) => {
4040
const fn = createFunctionExpression(
4141
[],
4242
undefined, // no return, assign body later

0 commit comments

Comments
 (0)