Skip to content

Commit dfc36c4

Browse files
hi-ogawaOpenCode
andauthored
chore(rsc): align performance track payload with starter (#1321)
Co-authored-by: Hiroshi Ogawa <4232207+hi-ogawa@users.noreply.github.com> Co-authored-by: OpenCode <noreply@opencode.ai>
1 parent 31cdbb8 commit dfc36c4

4 files changed

Lines changed: 13 additions & 13 deletions

File tree

packages/plugin-rsc/examples/performance-track/README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ This example isolates React's Server Components performance tracks from SSR and
1515
5. Let the Home page resolve, then follow **About** to capture the same workload through client navigation and an on-demand RSC request. After the About page resolves, wait another second for React's deferred performance flush.
1616
6. Stop recording and inspect the **Server Components** tracks.
1717

18-
Both paths produce a nested pair of `SlowServerComponent` spans. The 500ms inner component only starts after the 300ms outer component resolves, so the two appear as a staircase in the Server Components track instead of overlapping. The initial path uses the normal SSR and injected Flight stream, while client navigation fetches a second ReactNode payload.
18+
Both paths produce a nested pair of `SlowServerComponent` spans. The 500ms inner component only starts after the 300ms outer component resolves, so the two appear as a staircase in the Server Components track instead of overlapping. The initial path uses the normal SSR and injected Flight stream, while client navigation fetches a second RSC payload.
1919

20-
## Payload shape
20+
## React compatibility
2121

22-
This fixture intentionally exports `RscPayload = ReactNode` and serializes a top-level React element. React's canary client can recover moved performance debug information from supported renderable root values. Frameworks that move this information into an arbitrary object or a derived promise may need to preserve React's internal `_debugInfo` themselves.
22+
React 19.2.8 emits timing data but can lose debug information moved from initialized child chunks onto their resolved values. Its performance flush only reads the chunk itself, so Chrome shows track markers without the async component spans. React [fixed this in #34839](https://github.com/facebook/react/pull/34839) by recovering moved debug information from the resolved value during the performance flush.
2323

24-
Waku [extends the recovery logic](https://github.com/dai-shi/waku/blob/3f88539dfd92aab9aa8db32a390d4eb8b143ee44/packages/waku/src/lib/vite-plugins/patch-rsdw.ts#L3) for its plain-object payload. Next.js [propagates `_debugInfo`](https://github.com/vercel/next.js/blob/153bf8ac5fa00888ef5fbb2b65cac12f0942a44f/packages/next/src/client/components/router-reducer/ppr-navigations.ts#L2250) onto framework-created promises. These are framework-specific integration details rather than requirements of `@vitejs/plugin-rsc` or the RSC protocol.
24+
Waku [applies equivalent recovery](https://github.com/dai-shi/waku/blob/3f88539dfd92aab9aa8db32a390d4eb8b143ee44/packages/waku/src/lib/vite-plugins/patch-rsdw.ts#L3) as a transform for React versions without the fix.
2525

26-
This fixture was verified with matching React packages at `19.3.0-canary-81e442ea-20260721`. React 19.2.8 emits timing data but loses moved debug information during the client performance flush, so Chrome shows track markers without component spans. See React's [debug-info recovery logic](https://github.com/facebook/react/blob/b740af2510de1e19fcb399abb862af26ff95ac80/packages/react-client/src/ReactFlightClient.js#L4518-L4535).
26+
This fixture was verified with matching React packages at `19.3.0-canary-81e442ea-20260721`.

packages/plugin-rsc/examples/performance-track/src/framework/entry.browser.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ async function main() {
2323
}, [])
2424

2525
React.useEffect(() => listenNavigation(fetchRscPayload), [])
26-
return payload
26+
return payload.root
2727
}
2828

2929
async function fetchRscPayload() {

packages/plugin-rsc/examples/performance-track/src/framework/entry.rsc.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,17 @@ import type { ReactNode } from 'react'
33
import { Root } from '../root.tsx'
44
import { parseRenderRequest } from './request.ts'
55

6-
// This fixture intentionally serializes the React tree itself instead of the
7-
// object-shaped payload used by larger examples. React can recover performance
8-
// debug info from a top-level React element, while arbitrary object wrappers
9-
// may need to preserve React's internal `_debugInfo` manually.
10-
export type RscPayload = ReactNode
6+
export type RscPayload = {
7+
root: ReactNode
8+
}
119

1210
export default { fetch: handler }
1311

1412
async function handler(request: Request): Promise<Response> {
1513
const renderRequest = parseRenderRequest(request)
16-
const payload: RscPayload = <Root url={renderRequest.url} />
14+
const payload: RscPayload = {
15+
root: <Root url={renderRequest.url} />,
16+
}
1717
const rscStream = renderToReadableStream<RscPayload>(payload)
1818

1919
if (renderRequest.isRsc) {

packages/plugin-rsc/examples/performance-track/src/framework/entry.ssr.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export async function renderHTML(
1212

1313
function SsrRoot() {
1414
payload ??= createFromReadableStream<RscPayload>(ssrStream)
15-
return React.use(payload)
15+
return React.use(payload).root
1616
}
1717

1818
const bootstrapScriptContent =

0 commit comments

Comments
 (0)