fix(vue): symmetric HeadStream vnodes for clean streaming hydration#748
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughThis PR modifies the Changes
Sequence DiagramsequenceDiagram
actor Browser
participant Server
participant HeadStream Client
participant Vue Hydration
Browser->>+Server: Request page
Server->>Server: Render HeadStream component
Server->>Server: Output `<script data-allow-mismatch="children">`...
Server-->>-Browser: Send HTML (streaming)
Note over Browser: HTML received with script placeholder
Browser->>+HeadStream Client: Parse & mount
HeadStream Client->>HeadStream Client: setup() returns script vnode
HeadStream Client-->>-Browser: Render `<script data-allow-mismatch="children">`
Note over Vue Hydration: Mismatch tolerant hydration
Vue Hydration->>Vue Hydration: Compare server & client vnodes
Vue Hydration->>Vue Hydration: data-allow-mismatch permits<br/>innerHTML differences
Vue Hydration->>Browser: ✓ Hydration succeeds
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes 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.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@examples/vite-ssr-vue-streaming/tests/streaming.spec.ts`:
- Around line 237-245: The test currently only asserts unsafe === 0 which can
vacuously pass if no streamed update scripts were present; update the test to
also assert that at least one script containing "window.__unhead__.push" was
found. Locate the page.evaluate that collects script nodes (variable unsafe) and
either return a second value for the total matched scripts or run a separate
evaluate to count scripts that include 'window.__unhead__.push' (ignoring those
with data-allow-mismatch), then add an assertion like
expect(totalMatched).toBeGreaterThan(0) in addition to the existing
expect(unsafe).toBe(0) so the test fails when the HeadStream injection path
produced no scripts.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f6b44fcd-1b90-40e6-806f-da59fb4851bc
📒 Files selected for processing (9)
examples/vite-ssr-vue-streaming/index.htmlexamples/vite-ssr-vue-streaming/src/App.vueexamples/vite-ssr-vue-streaming/src/entry-client.tsexamples/vite-ssr-vue-streaming/tests/streaming.spec.tspackages/unhead/src/stream/server.tspackages/vue/src/stream/client.tspackages/vue/src/stream/server.tspackages/vue/src/stream/vite.tspackages/vue/test/streaming.test.ts
💤 Files with no reviewable changes (1)
- examples/vite-ssr-vue-streaming/src/entry-client.ts
Streaming head updates were emitted as `<script innerHTML="...">` vnodes on the server but as `null` on the client, producing vnode-type hydration mismatches. `HeadStream` now emits a symmetric `<script data-allow-mismatch="children">` on both server and client. Server fills `innerHTML` with the pending suspense-chunk payload (or empty before the shell renders); client renders an empty script. Matching vnode types + `data-allow-mismatch` let Vue's hydrator silence the inner-text diff cleanly. Playwright adds a regression guard that every streamed head-update script carries `data-allow-mismatch` (and that at least one such script was injected so the check is non-vacuous).
769eb10 to
7b3ead1
Compare
🔗 Linked issue
N/A
❓ Type of change
📚 Description
Streaming head updates were emitted as
<script innerHTML="...">vnodes on the server but asnullon the client, producing vnode-type hydration mismatches in@unhead/vue's streaming mode.HeadStreamnow emits a symmetric<script data-allow-mismatch="children">on both server and client. Server fillsinnerHTMLwith the pending suspense-chunk payload (or empty before the shell renders); client renders an empty script. Matching vnode types +data-allow-mismatchlet Vue's hydrator silence the inner-text diff cleanly.Scope is intentionally narrow: only the
HeadStreamcomponent and its tests change here. The relatedprepareStreamingTemplateoutlet-split + example shell changes will follow in a separate PR.✅ Test plan
pnpm -F @unhead/vue test(147 passed)pnpm -C examples/vite-ssr-vue-streaming test— new Playwright regression guard asserts everywindow.__unhead__.pushscript carriesdata-allow-mismatch, and that at least one such script was injected (non-vacuous)Summary by CodeRabbit
Bug Fixes
Tests