Skip to content

Commit 96c0f13

Browse files
johnjenkinsJohn Jenkins
andauthored
fix(ssr): named slot dom order with serializeShadowRoot: 'scoped' components (#6300)
* fix(ssr): expand ::part css selectors for ssr `scoped` components * chore: lint * fix(ssr): `serializeShadowRoot: 'scoped'` named slot DOM order * chore: fix test --------- Co-authored-by: John Jenkins <[email protected]>
1 parent da24af6 commit 96c0f13

File tree

5 files changed

+91
-3
lines changed

5 files changed

+91
-3
lines changed

src/runtime/client-hydrate.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ function addSlot(
619619
parentVNode.$elm$.insertBefore(slot, parentVNode.$elm$.children[0]);
620620
} else {
621621
// Insert the new slot element before the slot comment
622-
node.parentNode.insertBefore(childVNode.$elm$, node);
622+
node.parentNode.insertBefore(slot, node);
623623
}
624624
addSlottedNodes(slottedNodes, slotId, slotName, node, childVNode.$hostId$);
625625

@@ -645,9 +645,9 @@ function addSlot(
645645
// Move slot comment node (to after any other comment nodes)
646646
parentVNode.$elm$.insertBefore(slot, parentVNode.$elm$.children[0]);
647647
}
648-
childRenderNodes.push(childVNode);
649648
}
650649

650+
childRenderNodes.push(childVNode);
651651
slotNodes.push(childVNode);
652652

653653
if (!parentVNode.$children$) {

src/runtime/test/hydrate-shadow-in-shadow.spec.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ describe('hydrate, shadow in shadow', () => {
6060
<mock:shadow-root>
6161
<slot></slot>
6262
</mock:shadow-root>
63-
<!---->
6463
<slot></slot>
6564
</cmp-b>
6665
</mock:shadow-root>

test/wdio/ssr-hydration/cmp.test.tsx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,4 +386,41 @@ describe('Sanity check SSR > Client hydration', () => {
386386

387387
await expect(getComputedStyle(childComponentPart).backgroundColor).toBe('rgb(255, 192, 203)'); // pink
388388
});
389+
390+
it('renders named slots in the correct order in the DOM in scoped components', async () => {
391+
if (document.querySelector('#stage')) {
392+
document.querySelector('#stage')?.remove();
393+
await browser.waitUntil(async () => !document.querySelector('#stage'));
394+
}
395+
const { html } = await renderToString(
396+
`
397+
<div>
398+
<ssr-order-wrap-cmp>
399+
<div slot="things">one</div>
400+
<div slot="things">2</div>
401+
<div slot="things">3</div>
402+
</ssr-order-wrap-cmp>
403+
</div>`,
404+
{
405+
fullDocument: true,
406+
serializeShadowRoot: 'scoped',
407+
},
408+
);
409+
const stage = document.createElement('div');
410+
stage.setAttribute('id', 'stage');
411+
stage.setHTMLUnsafe(html);
412+
document.body.appendChild(stage);
413+
414+
// @ts-expect-error resolved through WDIO
415+
const { defineCustomElements } = await import('/dist/loader/index.js');
416+
defineCustomElements().catch(console.error);
417+
418+
// wait for Stencil to take over and reconcile
419+
await browser.waitUntil(async () => customElements.get('ssr-order-wrap-cmp'));
420+
expect(typeof customElements.get('ssr-order-wrap-cmp')).toBe('function');
421+
422+
const nestedCmp = document.querySelector('ssr-order-wrap-cmp').shadowRoot.querySelector('ssr-order-cmp');
423+
expect((nestedCmp.childNodes[0] as HTMLElement).tagName).toBe('SLOT');
424+
expect(nestedCmp.childNodes[1].textContent).toBe('after');
425+
});
389426
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Component, h, Host } from '@stencil/core';
2+
3+
@Component({
4+
tag: 'ssr-order-cmp',
5+
shadow: true,
6+
styles: `
7+
:host {
8+
display: block;
9+
border: 3px solid red;
10+
}
11+
`,
12+
})
13+
export class MyApp {
14+
render() {
15+
return (
16+
<Host>
17+
<div>
18+
<slot />
19+
</div>
20+
</Host>
21+
);
22+
}
23+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Component, h, Host } from '@stencil/core';
2+
3+
@Component({
4+
tag: 'ssr-order-wrap-cmp',
5+
shadow: true,
6+
styles: `
7+
:host {
8+
display: block;
9+
border: 3px solid blue;
10+
}
11+
`,
12+
})
13+
export class MyApp {
14+
render() {
15+
return (
16+
<Host>
17+
<div>
18+
<ssr-order-cmp>
19+
<slot name="things" />
20+
<div class="AFTER">after</div>
21+
</ssr-order-cmp>
22+
<div>
23+
<slot />
24+
</div>
25+
</div>
26+
</Host>
27+
);
28+
}
29+
}

0 commit comments

Comments
 (0)