Skip to content

Conversation

@schiller-manuel
Copy link
Contributor

@schiller-manuel schiller-manuel commented Sep 19, 2025

fixes #5155

Summary by CodeRabbit

  • Bug Fixes

    • Improved server-side rendering stability by correctly finalizing the initial render before injecting additional HTML, preventing rare hangs or incomplete pages.
    • Applies to both React and Solid router SSR paths.
  • Performance

    • Slightly reduces SSR latency by signaling render completion earlier in the pipeline.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 19, 2025

Walkthrough

Adds 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

Cohort / File(s) Summary
SSR render completion signaling
packages/react-router/src/ssr/renderRouterToString.tsx, packages/solid-router/src/ssr/renderRouterToString.tsx
After initial HTML render, invoke router.serverSsr!.setRenderFinished() before awaiting router.serverSsr!.injectedHtml; rest of SSR flow and error handling unchanged.

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
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

I rendered once, then tapped the bell,
“It’s finished!” I declared—can you tell? 🐇
Streams aligned, no longer stuck,
HTML stitched with bunny luck.
Now pages flow without delay—
hop, hop, hooray for SSR today!

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "fix: tell router that rendering finished when rendering to string" accurately and concisely summarizes the primary change: calling router.serverSsr!.setRenderFinished() after the initial render in the SSR helpers (packages/react-router/src/ssr/renderRouterToString.tsx and packages/solid-router/src/ssr/renderRouterToString.tsx), which is the key fix the author implemented. It is specific, actionable, and clear for a teammate scanning the history.
Linked Issues Check ✅ Passed The change calls setRenderFinished() immediately after the initial render in both React and Solid SSR renderers, which directly addresses the linked issue #5155 where an unresolved SSR promise prevented completion by ensuring the server-side serialization flow can proceed and injectedHtml/onSerialize can resolve. The PR makes this single targeted change without altering signatures or exports, aligning with the objective of ensuring SSR finishes when using setupRouterSsrQueryIntegration.
Out of Scope Changes Check ✅ Passed All modifications are limited to adding a single router.serverSsr!.setRenderFinished() call in two SSR helper files; there are no changes to public APIs, exports, or other unrelated modules, so I detect no out-of-scope changes.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-5155

Comment @coderabbitai help to get the list of available commands and usage tips.

@nx-cloud
Copy link

nx-cloud bot commented Sep 19, 2025

View your CI Pipeline Execution ↗ for commit 0f5c6b6

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 4m 25s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 31s View ↗

☁️ Nx Cloud last updated this comment at 2025-09-19 23:22:52 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Sep 19, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@5174

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@5174

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@5174

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@5174

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@5174

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@5174

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@5174

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@5174

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@5174

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@5174

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@5174

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@5174

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@5174

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@5174

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@5174

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@5174

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@5174

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@5174

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@5174

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@5174

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@5174

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@5174

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@5174

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@5174

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@5174

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@5174

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@5174

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@5174

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@5174

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@5174

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@5174

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@5174

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@5174

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@5174

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@5174

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@5174

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@5174

commit: 0f5c6b6

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 hangs

Recommend 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 await

Mirror 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

📥 Commits

Reviewing files that changed from the base of the PR and between f5872df and 0f5c6b6.

📒 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 hang

Same 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 paths

renderRouterToString (react/solid) calls router.serverSsr!.setRenderFinished; streaming paths rely on router-core transforms which call setRenderFinished (packages/router-core/src/ssr/transformStreamWithRouter.ts).

@schiller-manuel schiller-manuel merged commit 1d5c5f7 into main Sep 19, 2025
6 checks passed
@schiller-manuel schiller-manuel deleted the fix-5155 branch September 19, 2025 23:34
@coderabbitai coderabbitai bot mentioned this pull request Oct 20, 2025
@coderabbitai coderabbitai bot mentioned this pull request Nov 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

using setupRouterSsrQueryIntegration let ssr never finish with renderRouterToString

2 participants