mirror of
https://github.com/vercel/next.js.git
synced 2026-09-20 02:25:18 +08:00
985394417f
### What?
Fix a race condition in the Pages Router SSR path where styled-jsx
styles were dropped from the rendered HTML.
### Why?
`styledJsxInsertedHTML()` reads and flushes the styled-jsx style
registry. Previously it was 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 (and
in practice did) execute and flush the registry **before** the page
render had finished populating it. The result was that dynamic
styled-jsx styles — those with interpolated expressions that compute
their class names at runtime via DJB2 hashing — were silently dropped
from the SSR output, causing a flash of unstyled content on first load.
This is particularly visible in production deployments where all
components use dynamic styled-jsx (numeric `jsx-*` class names), since
those styles only exist in the registry after rendering completes.
### How?
Serialize the two operations: render the page first, then call
`styledJsxInsertedHTML()`. Since the registry is fully populated by the
time it is read, all styles are captured correctly.
A new e2e test (`test/e2e/styled-jsx-dynamic`) exercises this scenario
with multiple nested components that all use dynamic styled-jsx with
interpolated props, covering the exact FOUC pattern seen in production.
<!-- NEXT_JS_LLM_PR -->
Co-authored-by: Tobias Koppers <sokra@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
13 lines
203 B
JavaScript
13 lines
203 B
JavaScript
export default function DynamicStyled({ color }) {
|
|
return (
|
|
<div>
|
|
<style jsx>{`
|
|
p {
|
|
color: ${color};
|
|
}
|
|
`}</style>
|
|
<p>dynamic styled</p>
|
|
</div>
|
|
)
|
|
}
|