Skip to content

fix(router-core): read ssr.nonce lazily for hydration scripts - #8859

Open
aliassar wants to merge 2 commits into
TanStack:mainfrom
aliassar:fix-ssr-nonce-late-8789
Open

aliassar wants to merge 2 commits into
TanStack:mainfrom
aliassar:fix-ssr-nonce-late-8789

Conversation

@aliassar

@aliassar aliassar commented Nov 3, 2026 •

Copy link
Copy Markdown

🎯 Changes

Fixes #8789

#8204 started reading ssr.nonce once, when attachRouterServerSsrUtils runs, so a nonce set later (like in the createStartHandler callback from the issue) never reaches the hydration scripts. This passes a getter to createHydrationScripts so the nonce is read when the tags are built, the same way the bindings' other ssr.nonce reads work. The new test in transformStreamWithRouter.test.ts fails without the change. I also ran the issue's setup in a built Start app, and the stream-part and trailing scripts get the nonce again. I didn't add the docs or dev warning the issue offers as an alternative, since this restores the old behaviour.

Written with help from Claude Code; I reviewed and tested it.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested code changes locally with the relevant test commands, or tests do not apply to this pull request.
  • I fully understand the code in this pull request, including any code generated with AI assistance.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • Bug Fixes
    • Hydration scripts now use the current nonce when it is set after server-side rendering utilities are attached. The nonce is included on both the initial hydration script tags and the script emitted at the end of a streamed response, avoiding nonce-free script tags in this scenario.

createHydrationScripts received router.options.ssr?.nonce by value when the
SSR utils were attached, so a nonce set afterwards (for example in the
createStartHandler callback) never reached the hydration script tags.
Pass a getter and read it when the tags are built.

Fixes TanStack#8789

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: bf0adb2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 23 packages
Name Type
@tanstack/router-core Patch
@tanstack/react-router Patch
@tanstack/react-start-client Patch
@tanstack/react-start-rsc Patch
@tanstack/react-start-server Patch
@tanstack/router-generator Patch
@tanstack/router-plugin Patch
@tanstack/solid-router Patch
@tanstack/solid-start-client Patch
@tanstack/solid-start-server Patch
@tanstack/start-client-core Patch
@tanstack/start-plugin-core Patch
@tanstack/start-server-core Patch
@tanstack/start-storage-context Patch
@tanstack/vue-router Patch
@tanstack/vue-start-client Patch
@tanstack/vue-start-server Patch
@tanstack/react-start Patch
@tanstack/router-cli Patch
@tanstack/router-vite-plugin Patch
@tanstack/solid-start Patch
@tanstack/start-static-server-functions Patch
@tanstack/vue-start Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The hydration-script API now accepts a nonce supplier. The SSR server passes a getter for the router’s current SSR nonce. Initial hydration tags and the first dynamic script opening use the supplied nonce. A regression test covers a nonce set after SSR utilities attach.

Changes: SSR hydration nonce

Layer / File(s) Summary
Pass the current nonce
packages/router-core/src/ssr/hydrationScripts.ts, packages/router-core/src/ssr/ssr-server.ts, packages/router-core/tests/hydrationScripts.test.ts
The hydration-script API accepts a nonce supplier. The SSR server passes a callback that reads the router’s current SSR nonce. The unit-test helper now passes a callback.
Apply the nonce to hydration tags
packages/router-core/src/ssr/hydrationScripts.ts, packages/router-core/tests/transformStreamWithRouter.test.ts, .changeset/late-ssr-nonce-hydration.md
Initial hydration tags and the first dynamic script opening use the nonce returned by the supplier. The regression test sets the nonce after SSR utilities attach and checks the initial and stream-end scripts. A patch changeset records the update.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant SSRServer
  participant HydrationScriptsOwner
  participant RouterOptions
  SSRServer->>HydrationScriptsOwner: Pass nonce getter
  HydrationScriptsOwner->>RouterOptions: Read current ssr.nonce
  RouterOptions-->>HydrationScriptsOwner: Return nonce
  HydrationScriptsOwner-->>SSRServer: Create hydration script tags with nonce
Loading

Possibly related PRs

  • TanStack/router#8790: This PR also changes hydration-script creation to use a nonce getter and adds related regression coverage.

Suggested reviewers: schiller-manuel

Merge Risk: Minimal · up to bf0ad

The change preserves the configured nonce on initial and streamed hydration scripts for the reported SSR timing scenario.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: reading router-core SSR nonces lazily for hydration scripts.
Description check Passed The description explains the problem, motivation, implementation, testing, AI assistance, checklist status, and release impact. It includes the required sections and a changeset.
Linked Issues check Passed Issue #8789 requires hydration scripts to use an ssr.nonce that is set after router creation and before rendering. The reviewed head meets this requirement. In packages/router-core/src/ssr/ssr-server.…
Out of Scope Changes check Passed All changed files relate to issue #8789. The changes are: a patch changeset for @tanstack/router-core (.changeset/late-ssr-nonce-hydration.md); the nonce supplier change in packages/router-core/src/ss…
Full details: Linked Issues check

Explanation

Issue #8789 requires hydration scripts to use an ssr.nonce that is set after router creation and before rendering. The reviewed head meets this requirement. In packages/router-core/src/ssr/ssr-server.ts, attachRouterServerSsrUtils now calls createHydrationScripts(() => router.options.ssr?.nonce), so the nonce is read when tags are built, not when SSR utilities attach. In packages/router-core/src/ssr/hydrationScripts.ts, HydrationScriptsOwner stores this getter. pullReady() calls this.getNonce?.() when it prepares dynamic stream-part output, and the cached opening (this.opening ??=) uses that value. This covers the streamed hydration script path named in the issue. The initial-tag path (createInitialTags receives a nonce value) and the trailing boundary script are in content truncated by the read tool. The initial take must resolve the getter before calling createInitialTags. The previous assessment recorded this path as verified, and the new regression test in packages/router-core/tests/transformStreamWithRouter.test.ts sets the nonce after attach and checks initial and stream-end script nonces. The issue's alternative (documentation and dev warning) is not required because the issue allows either behavior. Residual uncertainty: I could not read the initial-take call site directly, so this verdict relies on the visible wiring, the test description, and the prior assessment.

Full details: Out of Scope Changes check

Explanation

All changed files relate to issue #8789. The changes are: a patch changeset for @tanstack/router-core (.changeset/late-ssr-nonce-hydration.md); the nonce supplier change in packages/router-core/src/ssr/hydrationScripts.ts; the getter wiring in packages/router-core/src/ssr/ssr-server.ts; a one-line call-site update in packages/router-core/tests/hydrationScripts.test.ts to match the new signature; and a regression test in packages/router-core/tests/transformStreamWithRouter.test.ts. The raw summary reports no changes to exported declarations beyond the createHydrationScripts parameter type, which is internal to the nonce path. No unrelated production behavior appears in the summary or in the visible source. No ignored files apply.

Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 1 functions across 4 files.

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share
Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 739d8f3 and bf0adb2.

Files selected for processing: 1
  • packages/router-core/tests/transformStreamWithRouter.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

@coderabbitai coderabbitai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • Fix comments: Fix CodeRabbit comments on this PR

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ssr.nonce set after the router is created no longer reaches the hydration scripts (regression in 1.171.31)

1 participant