Skip to content

Commit 1bb4a7d

Browse files
committed
Use extraHead to support nested components
1 parent 545fc35 commit 1bb4a7d

File tree

4 files changed

+48
-7
lines changed

4 files changed

+48
-7
lines changed

packages/astro/test/fixtures/solid-component/src/components/async-components.jsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,21 @@ const SLEEP_MS = 10;
66

77
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
88

9-
export function AsyncComponent() {
9+
export function AsyncComponent(props) {
1010
const [data] = createResource(async () => {
11-
await sleep(SLEEP_MS);
11+
// console.log("Start rendering async component " + props.title);
12+
await sleep(props.delay ?? SLEEP_MS);
13+
// console.log("Finish rendering async component " + props.title);
1214
return 'async_result_from_async_component';
1315
});
1416

1517
return (
1618
<div data-name="AsyncComponent" onClick={() => actions.refetch()}>
1719
{data()}
20+
{/* NOTE: The props.children are intentionally commented out
21+
to simulate a situation where hydration script might not
22+
be injected in the right spot. */}
23+
{/* {props.children} */}
1824
</div>
1925
);
2026
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
import { AsyncComponent } from '../components/async-components.jsx';
3+
---
4+
5+
<html>
6+
<head><title>Nested Test</title></head>
7+
<body>
8+
<div>
9+
<AsyncComponent client:load title="level-a">
10+
<AsyncComponent client:load title="level-a-a" ></AsyncComponent>
11+
<AsyncComponent client:load title="level-a-b">
12+
<AsyncComponent client:load title="level-a-b-a"></AsyncComponent>
13+
</AsyncComponent>
14+
<AsyncComponent client:load title="level-a-2" ></AsyncComponent>
15+
</AsyncComponent>
16+
</div>
17+
</body>
18+
</html>

packages/astro/test/solid-component.test.js

+9
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ describe('Solid component', () => {
8383
const hydrationScriptCount = countHydrationScripts(html);
8484
expect(hydrationScriptCount).to.be.equal(0);
8585
});
86+
87+
// nested.astro
88+
89+
it('Injects hydration script before any SolidJS components in the HTML, even if heavily nested', async () => {
90+
const html = await fixture.readFile('nested/index.html');
91+
const firstHydrationScriptAt = String(html).indexOf('_$HY=');
92+
const firstHydrationEventAt = String(html).indexOf('_$HY.set');
93+
expect(firstHydrationScriptAt).to.be.lessThan(firstHydrationEventAt);
94+
});
8695
});
8796

8897
if (isWindows) return;

packages/integrations/solid/src/server.ts

+13-5
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,23 @@ async function renderToStaticMarkup(
102102

103103
if (needsHydrate && renderStrategy === 'async') {
104104
if (!ctx.hasHydrationScript) {
105-
// Add the hydration script to the first hydrating component of the page
105+
// The hydration script needs to come before to the first hydrating component of the page.
106+
// One way to this would be to prepend the rendered output, eg:
107+
//
108+
// html += generateHydrationScript();
109+
//
110+
// However, in certain situations, nested components may be rendered depth-first, causing SolidJS
111+
// to put the hydration script in the wrong spot.
112+
//
113+
// Therefore we render the hydration script to the extraHead so it can work anytime.
114+
106115
// NOTE: It seems that components on a page may be rendered in parallel.
107-
// To avoid a race condition, this code block is intentially written
116+
// To avoid a race condition, this code block is intentionally written
108117
// *before* the first `await` in the function, so the hydration script will
109118
// be prefixed to the first hydratable component on the page, regardless of
110119
// the order in which the components finish rendering.
111-
html += generateHydrationScript();
112-
// I tried using extraHead but it did not work?
113-
// this.result.extraHead.push(generateHydrationScript());
120+
121+
this.result.extraHead.push(generateHydrationScript());
114122
ctx.hasHydrationScript = true;
115123
}
116124
}

0 commit comments

Comments
 (0)