From eb475356664e2cd3ec3eb8be6dbc227f1b227205 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 13 Oct 2026 19:16:18 +0000 Subject: [PATCH] fix(ssr): strip the shell-end marker from client-mode shells @solidjs/web 2.0.0-rc.15 (solidjs/solid#4002) ends every shell that rendered with an unguarded `_$HY.s[id]=1` script. Client mode already strips the HydrationScript bootstrap from a Document shared with SSR mode, so the marker was left behind and threw `_$HY is not defined`. Strip it with the bootstrap. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01R2FCNsvaipU3xXx9p83VUs --- .changeset/client-mode-shell-end-marker.md | 5 +++++ src/ssr/index.ts | 14 +++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 .changeset/client-mode-shell-end-marker.md diff --git a/.changeset/client-mode-shell-end-marker.md b/.changeset/client-mode-shell-end-marker.md new file mode 100644 index 0000000..6795040 --- /dev/null +++ b/.changeset/client-mode-shell-end-marker.md @@ -0,0 +1,5 @@ +--- +'@solidjs/vite-plugin': patch +--- + +Client start mode now strips the shell-end marker script along with the `` bootstrap. `@solidjs/web` 2.0.0-rc.15 (solidjs/solid#4002) closes every shell that rendered `` with ``, and a Document shared with SSR mode carries ``. Once the plugin stripped the bootstrap, that marker threw `_$HY is not defined` in client-mode shells, in dev and in the prerendered `index.html`. Shells from earlier `@solidjs/web` versions have no marker and are unchanged. diff --git a/src/ssr/index.ts b/src/ssr/index.ts index d4491c3..6c8a026 100644 --- a/src/ssr/index.ts +++ b/src/ssr/index.ts @@ -1397,8 +1397,20 @@ export function startServe( ); } lines.push(` chunk = chunk.replace('', ${headParts.join(' + ')} + '');`); + lines.push(` }`); + if (clientMode) { + // The shell-end marker (@solidjs/web 2.0.0-rc.15, solidjs/solid#4002) + // closes every shell that rendered ``. It writes to + // `_$HY` without a guard, so it goes with the bootstrap stripped above; + // left alone it throws `_$HY is not defined`. It follows the shell's + // records rather than its head, so it is matched in any chunk. + lines.push( + ` if (chunk.includes('_$HY.s[')) {`, + ` chunk = chunk.replace(/]*)?>_\\$HY\\.s\\[[\\s\\S]*?<\\/script>/, '');`, + ` }`, + ); + } lines.push( - ` }`, ` if (first) { first = false; chunk = '' + chunk; }`, ` return chunk;`, ` };`,