Skip to content

Conversation

@schiller-manuel
Copy link
Contributor

@schiller-manuel schiller-manuel commented Nov 15, 2025

Summary by CodeRabbit

  • Refactor

    • Improved server-side rendering script buffering and injection for more reliable timing and lifecycle handling.
    • Client head rendering now includes buffered SSR scripts when available.
    • Enhanced hydration/state tracking and post-hydration cleanup, plus a new global SSR marker.
  • Bug Fixes

    • Manifest generation now excludes routes with no associated data.
  • Chores

    • Removed an internal documentation comment (no runtime change).

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 15, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Introduces server-side SSR script buffering (ScriptBuffer) and exposes router.serverSsr.takeBufferedScripts(); integrates buffered scripts into React and Solid HeadContent with nonce/class; extends global SSR typings and client hydration flow (hydrated/streamEnd) with cleanup; refines route manifest to omit routes without preload/assets.

Changes

Cohort / File(s) Summary
SSR server buffering & flow
packages/router-core/src/ssr/ssr-server.ts
Added internal ScriptBuffer to enqueue/buffer SSR scripts, barrier control, replaced immediate injection with buffering, added takeBufferedScripts() API, and flush on render-finish.
Server SSR API surface
packages/router-core/src/router.ts
Added takeBufferedScripts(): string | undefined to ServerSsr interface.
Client SSR typing & hydration
packages/router-core/src/ssr/constants.ts, packages/router-core/src/ssr/ssr-client.ts
Added GLOBAL_SEROVAL constant; extended global TsrSsrGlobal with hydrated?: boolean and streamEnd?: boolean; set hydrated and invoke cleanup post-hydration.
TSR cleanup logic
packages/router-core/src/ssr/tsrScript.ts
c() now removes self.$_TSR and self.$R['tsr'] when both hydrated and streamEnd are true (in addition to existing element cleanup).
Head content integration (React & Solid)
packages/react-router/src/HeadContent.tsx, packages/solid-router/src/HeadContent.tsx
Call router.serverSsr.takeBufferedScripts() when available; if present, create a serverHeadScript tag (script, nonce, class $tsr) and include it in deduped head tags.
Minor doc/comment change
packages/react-router/src/ScriptOnce.tsx
Removed one documentation comment line; no runtime change.
Manifest pruning
packages/start-server-core/src/router-manifest.ts
Stop spreading entire startManifest; include per-route preloads/assets only when present (length>0); omit routes with no data.

Sequence Diagram

sequenceDiagram
    participant Server as SSR Server
    participant Buffer as ScriptBuffer
    participant RouterSSR as router.serverSsr
    participant Client as Client (Hydrate)
    participant Head as HeadContent

    Server->>Buffer: enqueue serialized scripts (onSerialize)
    Server->>Buffer: enqueue streamEnd (onDone)
    Note over Buffer: Barrier holds emission until liftBarrier()
    Server->>Buffer: liftBarrier() when render finished

    Client->>RouterSSR: call takeBufferedScripts()
    RouterSSR->>Buffer: retrieve & clear buffered scripts
    Buffer-->>RouterSSR: script string | undefined
    RouterSSR-->>Client: return buffered scripts

    Client->>Client: run hydrate hook
    Client->>Client: set hydrated = true
    Client->>Client: call c() cleanup
    Note over Client: if hydrated && streamEnd → remove globals

    Client->>Head: include serverHeadScript (nonce, class `$tsr`) if present
    Head->>Client: render/inject script tag
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas needing extra attention:

  • packages/router-core/src/ssr/ssr-server.ts — ScriptBuffer concurrency/barrier, enqueue vs immediate injection, interaction with takeBufferedScripts and liftBarrier.
  • packages/router-core/src/ssr/ssr-client.ts & tsrScript.ts — hydration/streamEnd flag timing and cleanup correctness.
  • packages/react-router/src/HeadContent.tsx & packages/solid-router/src/HeadContent.tsx — nonce propagation, className, and deduplication interaction.
  • packages/start-server-core/src/router-manifest.ts — manifest shape changes and potential consumers relying on previous spread.

Possibly related PRs

Suggested reviewers

  • birkskyum

Poem

🐰 I buffered scripts in a cozy heap,
Waiting politely until SSR's sleep,
Barriers lifted, the stream said "done",
Hydration finished — globals are shunned,
Hop, nibble, deploy — the rabbit's job's fun! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: cleanup streamed values' directly describes the main objective across multiple files—introducing cleanup logic for buffered/streamed SSR scripts.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a272ef0 and 27ee15b.

📒 Files selected for processing (1)
  • packages/router-core/src/ssr/constants.ts (1 hunks)

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

@nx-cloud
Copy link

nx-cloud bot commented Nov 15, 2025

🤖 Nx Cloud AI Fix Eligible

An automatically generated fix could have helped fix failing tasks for this run, but Self-healing CI is disabled for this workspace. Visit workspace settings to enable it and get automatic fixes in future runs.

To disable these notifications, a workspace admin can disable them in workspace settings.


View your CI Pipeline Execution ↗ for commit 27ee15b

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ❌ Failed 7m 53s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 24s View ↗

☁️ Nx Cloud last updated this comment at 2025-11-15 01:02:21 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 15, 2025

More templates

@tanstack/arktype-adapter

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

@tanstack/directive-functions-plugin

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

@tanstack/eslint-plugin-router

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

@tanstack/history

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

@tanstack/nitro-v2-vite-plugin

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

@tanstack/react-router

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

@tanstack/react-router-devtools

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

@tanstack/react-router-ssr-query

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

@tanstack/react-start

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

@tanstack/react-start-client

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

@tanstack/react-start-server

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

@tanstack/router-cli

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

@tanstack/router-core

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

@tanstack/router-devtools

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

@tanstack/router-devtools-core

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

@tanstack/router-generator

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

@tanstack/router-plugin

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

@tanstack/router-ssr-query-core

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

@tanstack/router-utils

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

@tanstack/router-vite-plugin

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

@tanstack/server-functions-plugin

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

@tanstack/solid-router

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

@tanstack/solid-router-devtools

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

@tanstack/solid-router-ssr-query

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

@tanstack/solid-start

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

@tanstack/solid-start-client

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

@tanstack/solid-start-server

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

@tanstack/start-client-core

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

@tanstack/start-plugin-core

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

@tanstack/start-server-core

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

@tanstack/start-static-server-functions

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

@tanstack/start-storage-context

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

@tanstack/valibot-adapter

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

@tanstack/virtual-file-routes

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

@tanstack/zod-adapter

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

commit: a272ef0

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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 559856b and a272ef0.

📒 Files selected for processing (9)
  • packages/react-router/src/HeadContent.tsx (2 hunks)
  • packages/react-router/src/ScriptOnce.tsx (0 hunks)
  • packages/router-core/src/router.ts (1 hunks)
  • packages/router-core/src/ssr/constants.ts (1 hunks)
  • packages/router-core/src/ssr/ssr-client.ts (3 hunks)
  • packages/router-core/src/ssr/ssr-server.ts (7 hunks)
  • packages/router-core/src/ssr/tsrScript.ts (1 hunks)
  • packages/solid-router/src/HeadContent.tsx (1 hunks)
  • packages/start-server-core/src/router-manifest.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/react-router/src/ScriptOnce.tsx
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-11-02T16:16:24.898Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5732
File: packages/start-client-core/src/client/hydrateStart.ts:6-9
Timestamp: 2025-11-02T16:16:24.898Z
Learning: In packages/start-client-core/src/client/hydrateStart.ts, the `import/no-duplicates` ESLint disable is necessary for imports from `#tanstack-router-entry` and `#tanstack-start-entry` because both aliases resolve to the same placeholder file (`fake-start-entry.js`) in package.json during static analysis, even though they resolve to different files at runtime.

Applied to files:

  • packages/router-core/src/ssr/ssr-client.ts
  • packages/start-server-core/src/router-manifest.ts
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/start-server-core/src/router-manifest.ts
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.

Applied to files:

  • packages/start-server-core/src/router-manifest.ts
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/start-server-core/src/router-manifest.ts
🧬 Code graph analysis (3)
packages/react-router/src/HeadContent.tsx (1)
packages/react-router/src/useRouterState.tsx (1)
  • useRouterState (48-76)
packages/router-core/src/ssr/ssr-client.ts (1)
packages/router-core/src/ssr/constants.ts (1)
  • GLOBAL_TSR (1-1)
packages/router-core/src/ssr/ssr-server.ts (3)
packages/router-core/src/router.ts (1)
  • AnyRouter (768-768)
packages/router-core/src/ssr/constants.ts (1)
  • GLOBAL_TSR (1-1)
packages/router-core/src/ssr/tsrScript.ts (1)
  • p (11-13)
⏰ 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 (1)
packages/start-server-core/src/router-manifest.ts (1)

46-57: LGTM! Clean filtering of routes without data.

The hasData flag and conditional return pattern correctly filter out routes that have neither preloads nor assets. The explicit length checks handle both undefined and empty array cases properly. Since the root route is guaranteed to have at least one asset (the client entry script added at line 28), it won't be inadvertently filtered.

@@ -1 +1,2 @@
export const GLOBAL_TSR = '$_TSR'
export declare const GLOBAL_SEROVAL = '$R'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix the invalid constant declaration

Line 2 uses export declare const … = …, which is illegal in a .ts module (ambient declarations cannot have initializers). This will make TypeScript fail to compile. Please switch to a normal constant export.

-export declare const GLOBAL_SEROVAL = '$R'
+export const GLOBAL_SEROVAL = '$R'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export declare const GLOBAL_SEROVAL = '$R'
export const GLOBAL_SEROVAL = '$R'
🤖 Prompt for AI Agents
In packages/router-core/src/ssr/constants.ts around line 2, the file currently
uses an ambient declaration with an initializer ("export declare const ... =
...") which is illegal in a TS module; change it to a normal exported constant
by removing the "declare" keyword (e.g., use "export const GLOBAL_SEROVAL =
'$R'") so the initializer is allowed and the module compiles.

Comment on lines +9 to 15
import type { GLOBAL_SEROVAL, GLOBAL_TSR } from './constants'

declare global {
interface Window {
[GLOBAL_TSR]?: TsrSsrGlobal
[GLOBAL_SEROVAL]?: any
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Import the constants as runtime values

GLOBAL_TSR (and the new GLOBAL_SEROVAL) are exported as runtime constants, so import type { … } cannot resolve them—TypeScript reports “has no exported member” and compilation stops. Bring them in as normal value imports instead.

-import type { GLOBAL_SEROVAL, GLOBAL_TSR } from './constants'
+import { GLOBAL_SEROVAL, GLOBAL_TSR } from './constants'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { GLOBAL_SEROVAL, GLOBAL_TSR } from './constants'
declare global {
interface Window {
[GLOBAL_TSR]?: TsrSsrGlobal
[GLOBAL_SEROVAL]?: any
}
import { GLOBAL_SEROVAL, GLOBAL_TSR } from './constants'
declare global {
interface Window {
[GLOBAL_TSR]?: TsrSsrGlobal
[GLOBAL_SEROVAL]?: any
}
🤖 Prompt for AI Agents
In packages/router-core/src/ssr/ssr-client.ts around lines 9 to 15, the file
imports GLOBAL_TSR and GLOBAL_SEROVAL using "import type" but those are
runtime-exported constants and must be imported as actual values; change the
import to a normal value import (remove "type") so the constants are available
at runtime, keep any type-only imports as "import type" if needed, and update
any references to use the imported runtime values; rebuild to ensure TypeScript
no longer reports the missing exported member error.

@schiller-manuel schiller-manuel merged commit af77b55 into main Nov 15, 2025
3 of 5 checks passed
@schiller-manuel schiller-manuel deleted the cleanup-stream branch November 15, 2025 00:53
This was referenced Nov 18, 2025
roduyemi pushed a commit to roduyemi/oss-router that referenced this pull request Nov 19, 2025
@coderabbitai coderabbitai bot mentioned this pull request Dec 21, 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.

2 participants