Skip to content

Commit

Permalink
fix(ssr): missing bookends for slotted lwc:if not at the top-level (#…
Browse files Browse the repository at this point in the history
…5027)

Co-authored-by: Nolan Lawson <[email protected]>
  • Loading branch information
cardoso and nolanlawson authored Dec 18, 2024
1 parent c5c7458 commit bcd22de
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ export const expectedFailures = new Set([
'scoped-slots/mixed-with-light-dom-slots-outside/index.js',
'slot-forwarding/slots/mixed/index.js',
'slot-forwarding/slots/dangling/index.js',
'slot-not-at-top-level/advanced/lwcIf/light/index.js',
'slot-not-at-top-level/advanced/lwcIf/shadow/index.js',
'slot-not-at-top-level/lwcIf-with-adjacent-text-nodes/light/index.js',
'slot-not-at-top-level/nested-elements/lwcIf/shadow/index.js',
'superclass/render-in-superclass/no-template-in-subclass/index.js',
'superclass/render-in-superclass/unused-default-in-subclass/index.js',
'superclass/render-in-superclass/unused-default-in-superclass/index.js',
Expand Down
22 changes: 16 additions & 6 deletions packages/@lwc/ssr-compiler/src/compile-template/ir-to-es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,24 @@ const transformers: Transformers = {
Lwc: LwcComponent,
};

export function irChildrenToEs(children: IrChildNode[], cxt: TransformerContext): EsStatement[] {
const result = children.flatMap((child, idx) => {
cxt.prevSibling = children[idx - 1];
cxt.nextSibling = children[idx + 1];
return irToEs(child, cxt);
});
export function irChildrenToEs(
children: IrChildNode[],
cxt: TransformerContext,
cb?: (child: IrChildNode) => (() => void) | void
): EsStatement[] {
const result: EsStatement[] = [];

for (let i = 0; i < children.length; i++) {
cxt.prevSibling = children[i - 1];
cxt.nextSibling = children[i + 1];
const cleanUp = cb?.(children[i]);
result.push(...irToEs(children[i], cxt));
cleanUp?.();
}

cxt.prevSibling = undefined;
cxt.nextSibling = undefined;

return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,23 @@ const bAddLightContent = esTemplate`
});
`<EsCallExpression>;

function getShadowSlottedContent(slottableChildren: IrChildNode[], cxt: TransformerContext) {
return optimizeAdjacentYieldStmts(
irChildrenToEs(slottableChildren, cxt, (child) => {
const { isSlotted } = cxt;

if (child.type === 'ExternalComponent' || child.type === 'Element') {
cxt.isSlotted = false;
}

// cleanup function
return () => {
cxt.isSlotted = isSlotted;
};
})
);
}

// Light DOM slots are a bit complex because of needing to handle slots _not_ at the top level
// At the non-top level, it matters what the ancestors are. These are relevant to slots:
// - If (`if:true`, `if:false`)
Expand Down Expand Up @@ -130,7 +147,10 @@ function getLightSlottedContent(rootNodes: IrChildNode[], cxt: TransformerContex
leaf.attributes = leaf.attributes.filter((attr) => attr.name !== 'slot');
}
});
const { isSlotted: originalIsSlotted } = cxt;
cxt.isSlotted = ancestorIndices.length > 1 || clone.type === 'Slot';
const slotContent = irToEs(clone, cxt);
cxt.isSlotted = originalIsSlotted;
results.push(b.expressionStatement(bAddLightContent(slotName, null, slotContent)));
};

Expand Down Expand Up @@ -180,7 +200,7 @@ export function getSlottedContent(
(child) => child.type === 'ScopedSlotFragment'
) as IrScopedSlotFragment[];

const shadowSlotContent = optimizeAdjacentYieldStmts(irChildrenToEs(slottableChildren, cxt));
const shadowSlotContent = getShadowSlottedContent(slottableChildren, cxt);

const lightSlotContent = getLightSlottedContent(slottableChildren, cxt);

Expand Down

0 comments on commit bcd22de

Please sign in to comment.