feat(stream): split template at <!--app-html--> / <!--ssr-outlet--> marker#753
feat(stream): split template at <!--app-html--> / <!--ssr-outlet--> marker#753harlan-zw wants to merge 1 commit into
Conversation
`prepareStreamingTemplate` currently splits a template only at the body tag boundary, so a template like `<body><div id="app"><!--app-html--></div></body>` emits the shell up to `<body>` and then streams the app content as a sibling of `<div id="app">`. That produces a server-rendered DOM the client can't hydrate at `#app` without a container mismatch. If the body interior contains the canonical Vite SSR outlet marker (`<!--app-html-->` or `<!--ssr-outlet-->`), split there instead: everything before the marker is appended to the shell, everything after becomes the new body interior. Templates without a marker retain current behavior.
📝 WalkthroughWalkthroughThis change modifies the streaming template preparation logic to detect and handle Vite SSR outlet comment markers ( Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Bundle Size Analysis
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/unhead/test/streaming/streaming.test.ts (1)
425-455: Tighten assertions around the final assembled HTML.These tests cover the split, but they don’t currently prove the streamed app lands inside the outlet wrapper or that the marker is absent from
end. Adding round-trip assertions would pin the hydration contract more directly.🧪 Suggested test assertions
expect(shell).toContain('<title>Outlet Test</title>') expect(shell).toContain('<div id="app">') expect(shell).not.toContain('<!--app-html-->') + expect(end).not.toContain('<!--app-html-->') expect(end).toContain('</div></body></html>') + expect(`${shell}<span>app</span>${end}`).toContain('<div id="app"><span>app</span></div>') @@ expect(shell).toContain('<div id="root">') expect(shell).not.toContain('<!--ssr-outlet-->') + expect(end).not.toContain('<!--ssr-outlet-->') expect(end).toContain('</div></body></html>') + expect(`${shell}<span>app</span>${end}`).toContain('<div id="root"><span>app</span></div>')🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/unhead/test/streaming/streaming.test.ts` around lines 425 - 455, The tests currently only assert split points but don't verify the final assembled HTML nor that the streamed app content actually lands inside the outlet wrapper; update the three specs using createStreamableHead and prepareStreamingTemplate to perform a round-trip assertion: simulate the streamed app payload (e.g. an app fragment string), concatenate shell + app fragment + end, then assert the concatenated output contains the outlet wrapper with the app fragment inside, and assert the original outlet marker (<!--app-html--> or <!--ssr-outlet-->) is not present in shell, end, or the final concatenation; reference the prepareStreamingTemplate result variables shell and end and the createStreamableHead head usage when adding these assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/unhead/test/streaming/streaming.test.ts`:
- Around line 425-455: The tests currently only assert split points but don't
verify the final assembled HTML nor that the streamed app content actually lands
inside the outlet wrapper; update the three specs using createStreamableHead and
prepareStreamingTemplate to perform a round-trip assertion: simulate the
streamed app payload (e.g. an app fragment string), concatenate shell + app
fragment + end, then assert the concatenated output contains the outlet wrapper
with the app fragment inside, and assert the original outlet marker
(<!--app-html--> or <!--ssr-outlet-->) is not present in shell, end, or the
final concatenation; reference the prepareStreamingTemplate result variables
shell and end and the createStreamableHead head usage when adding these
assertions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e2f2d7cc-6ed2-4e74-8c06-24db12f2a182
📒 Files selected for processing (2)
packages/unhead/src/stream/server.tspackages/unhead/test/streaming/streaming.test.ts
|
Superseded by #752, which landed the same marker-splitting logic in |
🔗 Linked issue
N/A — surfaced while making the Vue streaming example use the canonical Vite outlet template.
❓ Type of change
📚 Description
`prepareStreamingTemplate` only split at the body tag boundary, so a canonical Vite SSR template like `<div id="app">` emitted the app stream as a sibling of `<div id="app">` and the client couldn't hydrate `#app` without a container mismatch. When the body interior contains `` or ``, we now split at that marker so the app stream lands inside the container. Templates without a marker keep current behavior.
Summary by CodeRabbit
Bug Fixes
Tests