mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #926] [MERGED] fix(app-router): flush server-inserted HTML during SSR streaming #954
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#954
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/926
Author: @NathanDrake2406
Created: 4/28/2026
Status: ✅ Merged
Merged: 4/28/2026
Merged by: @james-elicx
Base:
main← Head:nathan/fix-server-inserted-html-streaming📝 Commits (1)
abda7f4fix(app-router): flush server-inserted HTML during SSR streaming📊 Changes
6 files changed (+173 additions, -17 deletions)
View changed files
📝
packages/vinext/src/server/app-ssr-entry.ts(+28 -13)📝
packages/vinext/src/server/app-ssr-stream.ts(+26 -4)📝
packages/vinext/src/shims/navigation.react-server.ts(+1 -0)📝
packages/vinext/src/shims/navigation.ts(+22 -0)📝
tests/rsc-streaming.test.ts(+84 -0)📝
tests/server-inserted-html.test.ts(+12 -0)📄 Description
What this changes
App Router SSR now asks for
useServerInsertedHTMLoutput on each HTML streaming flush instead of only once before returning the stream. The first insertion still places the navigation/bootstrap/font/server HTML before</head>, while later insertions emit newly collected server-inserted HTML before the next streamed chunk.Why
CSS-in-JS registries such as styled-components and Emotion register a callback during shell render, then collect additional styles as Suspense boundaries continue rendering. Vinext previously flushed and cleared those callbacks before the stream was consumed, so styles collected after the shell never reached streamed HTML.
Next.js keeps server-inserted HTML callbacks registered and asks for insertion HTML from its stream transform repeatedly:
createServerInsertedHTMLstores callbacks without clearing themmakeGetServerInsertedHTMLrenders the registered callbacks each time it is calledcreateHeadInsertionTransformStreaminvokes insertion during stream transforms and final flushApproach
renderServerInsertedHTML()for streaming SSR so callbacks can be invoked without unregistering them.createTickBufferedTransform()accept an insertion function and call it after the initial head injection on each buffered flush.Validation
vp checkvp test run tests/server-inserted-html.test.ts tests/server-inserted-html-context.test.ts tests/rsc-streaming.test.ts tests/app-router.test.ts tests/features.test.ts tests/app-page-stream.test.tsRisks / follow-ups
The change is scoped to App Router SSR streaming and the existing tick-buffered transform. The test coverage is unit and integration-level; it ports the Next.js streaming order assertion without adding a full styled-components dependency fixture to vinext.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.