-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix: tell router that rendering finished when rendering to string #5174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds a call to router.serverSsr!.setRenderFinished() immediately after the initial renderToString in both React and Solid SSR renderRouterToString implementations, before awaiting injectedHtml. No other logic or signatures are changed. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Client
participant Server
participant renderRouterToString as renderRouterToString
participant Router
participant SSR as serverSsr
participant TPL as Template/HTML
Client->>Server: HTTP request
Server->>renderRouterToString: invoke with Router + children
renderRouterToString->>TPL: renderToString(children)
TPL-->>renderRouterToString: initialHTML
renderRouterToString->>SSR: setRenderFinished()
Note right of SSR: Marks SSR data streams ready to finalize
renderRouterToString->>SSR: await injectedHtml
SSR-->>renderRouterToString: injectedHtml (serialized chunks)
renderRouterToString->>TPL: inject HTML before </body>
renderRouterToString-->>Server: Response(HTML)
Server-->>Client: HTML response
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests
Comment |
|
View your CI Pipeline Execution ↗ for commit 0f5c6b6
☁️ Nx Cloud last updated this comment at |
More templates
@tanstack/arktype-adapter
@tanstack/directive-functions-plugin
@tanstack/eslint-plugin-router
@tanstack/history
@tanstack/react-router
@tanstack/react-router-devtools
@tanstack/react-router-ssr-query
@tanstack/react-start
@tanstack/react-start-client
@tanstack/react-start-plugin
@tanstack/react-start-server
@tanstack/router-cli
@tanstack/router-core
@tanstack/router-devtools
@tanstack/router-devtools-core
@tanstack/router-generator
@tanstack/router-plugin
@tanstack/router-ssr-query-core
@tanstack/router-utils
@tanstack/router-vite-plugin
@tanstack/server-functions-plugin
@tanstack/solid-router
@tanstack/solid-router-devtools
@tanstack/solid-start
@tanstack/solid-start-client
@tanstack/solid-start-plugin
@tanstack/solid-start-server
@tanstack/start-client-core
@tanstack/start-plugin-core
@tanstack/start-server-core
@tanstack/start-server-functions-client
@tanstack/start-server-functions-fetcher
@tanstack/start-server-functions-server
@tanstack/start-storage-context
@tanstack/valibot-adapter
@tanstack/virtual-file-routes
@tanstack/zod-adapter
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
packages/solid-router/src/ssr/renderRouterToString.tsx (1)
17-19: Add a bounded wait to prevent future indefinite hangsRecommend guarding Promise.all with a timeout so a misbehaving injector can't stall SSR forever.
Apply this minimal change:
- const injectedHtml = await Promise.all(router.serverSsr!.injectedHtml).then( - (htmls) => htmls.join(''), - ) + const timeoutMs = 15000 + const injectedHtml = await Promise.race<string>([ + Promise.all(router.serverSsr!.injectedHtml).then((htmls) => htmls.join('')), + new Promise<string>((resolve) => + setTimeout(() => resolve('<!-- ssr injectedHtml timed out -->'), timeoutMs), + ), + ])If you prefer not to hardcode a timeout, expose it via router/serverSsr options and default here.
packages/react-router/src/ssr/renderRouterToString.tsx (1)
17-19: Defensive timeout around injectedHtml awaitMirror the bounded wait to avoid indefinite stalls if an injector never resolves.
- const injectedHtml = await Promise.all(router.serverSsr!.injectedHtml).then( - (htmls) => htmls.join(''), - ) + const timeoutMs = 15000 + const injectedHtml = await Promise.race<string>([ + Promise.all(router.serverSsr!.injectedHtml).then((htmls) => htmls.join('')), + new Promise<string>((resolve) => + setTimeout(() => resolve('<!-- ssr injectedHtml timed out -->'), timeoutMs), + ), + ])
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/react-router/src/ssr/renderRouterToString.tsx(1 hunks)packages/solid-router/src/ssr/renderRouterToString.tsx(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Test
- GitHub Check: Preview
🔇 Additional comments (3)
packages/solid-router/src/ssr/renderRouterToString.tsx (1)
16-16: LGTM: correct placement of setRenderFinished()Calling setRenderFinished() right after renderToString unblocks SSR consumers and addresses the hanging behavior.
Please confirm that after setRenderFinished(), serverSsr.injectedHtml is no longer appended to (or that the API guarantees a finalized list). If it can still grow, Promise.all on a pre‑iteration snapshot might miss late entries.
packages/react-router/src/ssr/renderRouterToString.tsx (2)
16-16: LGTM: render completion signal fixes SSR hangSame rationale as Solid: signaling completion before awaiting injections is the right lifecycle point.
As above, please confirm injectedHtml is finalized after setRenderFinished() so Promise.all can’t miss late pushes.
5-13: Resolved — setRenderFinished already invoked for string and stream SSR pathsrenderRouterToString (react/solid) calls router.serverSsr!.setRenderFinished; streaming paths rely on router-core transforms which call setRenderFinished (packages/router-core/src/ssr/transformStreamWithRouter.ts).
fixes #5155
Summary by CodeRabbit
Bug Fixes
Performance