You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Shell-end marker is written after </html> in fully assembled documents (rc.15, #4002) #4030
In @solidjs/web 2.0.0-rc.15, a render that outputs <HydrationScript /> ends its shell with the shell-end marker from #4002. When the shell is the whole document (async render mode, i.e. the sync/complete assembly path, or a streamed shell with nothing pending), the marker is appended after</html>:
Browsers still run the script, because the parser reprocesses it into <body>. But content after </html> is a parse error, and the document no longer ends with </html>.
Where
packages/web/src/server.ts, both call sites of shellEndMarker:
the complete-document path (assembleDocument(...) + shellEndMarker(...), around L1902)
the stream sink's shell() (assembleDocument(...) + shellEndMarker(...), around L2439)
Both add the marker to the end of the assembled string instead of splicing it into the document.
Expected
The marker should still run after every shell node, but inside the document: spliced in right before </body> when the assembled shell has one, and appended as now otherwise.
Downstream impact
@solidjs/vite-plugin's start-ssr suite checks that async-mode documents arrive as "doctype … </html> in one piece". Against rc.15, 7 of its 749 assertions fail (render-mode override, async dev and prod, per-request header mode, authored entries). Plugin CI will go red once its lockfile moves to rc.15. Client mode had a separate rc.15 problem, which is fixed plugin-side in solidjs/solid-vite-plugin#413.
Repro
In the examples/start-ssr folder of solid-vite-plugin next, with solid-js and @solidjs/web at 2.0.0-rc.15 (or packed from solid next at eae6e03), run SSR_RENDER_MODE=async vite. Then curl -H 'accept: text/html' localhost:5173/ | tail -c 200 shows the marker after </html>.
Fixed in #4034 (merged into next as c032934). The shell-end marker is now spliced in right before </body>, so a whole document ends with </html> again. That covers async render mode and a stream with nothing pending. A shell without </body>, such as an embedded render, still gets the marker appended. The renderToString floor was raised to 20.51 KB for it.
Activity
fix(web): splice the shell-end marker before </body> (#4030)
chore(size): raise the renderToString floor for the #4030 marker splice
Merge pull request #4034 from solidjs/claude/project-thread-zclbh4
ryansolid commentedon Oct 13, 2026
Generated by Claude Code