[GH-ISSUE #792] Audit Pages Router SSR for styled-jsx race condition (concurrent rendering drops dynamic styles) #174

Closed
opened 2026-05-06 12:37:52 +02:00 by BreizhHardware · 0 comments

Originally created by @github-actions[bot] on GitHub (Apr 8, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/792

Upstream change

Next.js fixed a race condition in Pages Router SSR where dynamic styled-jsx styles were silently dropped from rendered HTML.

Commit: 9853944 — "Fix styled-jsx race condition: styles lost due to concurrent rendering (#92459)"

What changed

In packages/next/src/server/render.tsx, styledJsxInsertedHTML() was previously called concurrently with the page render via Promise.all:

const [rawStyledJsxInsertedHTML, content] = await Promise.all([
  renderToString(styledJsxInsertedHTML()),
  (async () => { /* render the page */ })(),
])

Because both ran at the same time, styledJsxInsertedHTML() could flush the styled-jsx registry before the page render had finished populating it. Dynamic styled-jsx styles (those with interpolated expressions that compute class names at runtime via DJB2 hashing) were silently dropped from SSR output, causing a flash of unstyled content.

Fix: Serialize the operations — render the page first, then call styledJsxInsertedHTML().

Relevance to vinext

vinext reimplements Pages Router SSR in server/dev-server.ts and server/prod-server.ts. If vinext's SSR render path for Pages Router apps also reads the styled-jsx registry concurrently with (or before) page rendering completes, the same race condition could cause dynamic styled-jsx styles to be missing from SSR output.

Action items:

  1. Check whether vinext's Pages Router SSR path calls styledJsxInsertedHTML() or reads the styled-jsx registry
  2. If it does, verify the registry is read after page rendering completes (not concurrently)
  3. If the pattern exists, fix it and add a test with dynamic styled-jsx (interpolated expressions) to verify styles are present in SSR output
Originally created by @github-actions[bot] on GitHub (Apr 8, 2026). Original GitHub issue: https://github.com/cloudflare/vinext/issues/792 ## Upstream change Next.js fixed a race condition in Pages Router SSR where dynamic styled-jsx styles were silently dropped from rendered HTML. **Commit:** [`9853944`](https://github.com/vercel/next.js/commit/985394417f2ef72466238497576a060ca936821c) — "Fix styled-jsx race condition: styles lost due to concurrent rendering (#92459)" ## What changed In `packages/next/src/server/render.tsx`, `styledJsxInsertedHTML()` was previously called concurrently with the page render via `Promise.all`: ```js const [rawStyledJsxInsertedHTML, content] = await Promise.all([ renderToString(styledJsxInsertedHTML()), (async () => { /* render the page */ })(), ]) ``` Because both ran at the same time, `styledJsxInsertedHTML()` could flush the styled-jsx registry **before** the page render had finished populating it. Dynamic styled-jsx styles (those with interpolated expressions that compute class names at runtime via DJB2 hashing) were silently dropped from SSR output, causing a flash of unstyled content. **Fix:** Serialize the operations — render the page first, then call `styledJsxInsertedHTML()`. ## Relevance to vinext vinext reimplements Pages Router SSR in `server/dev-server.ts` and `server/prod-server.ts`. If vinext's SSR render path for Pages Router apps also reads the styled-jsx registry concurrently with (or before) page rendering completes, the same race condition could cause dynamic styled-jsx styles to be missing from SSR output. **Action items:** 1. Check whether vinext's Pages Router SSR path calls `styledJsxInsertedHTML()` or reads the styled-jsx registry 2. If it does, verify the registry is read **after** page rendering completes (not concurrently) 3. If the pattern exists, fix it and add a test with dynamic styled-jsx (interpolated expressions) to verify styles are present in SSR output
BreizhHardware 2026-05-06 12:37:52 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#174
No description provided.