Skip to content

fix(router-core): lane match loader rewrite#7805

Open
Sheraff wants to merge 12 commits into
mainfrom
fix-router-core-lane-match-loader
Open

fix(router-core): lane match loader rewrite#7805
Sheraff wants to merge 12 commits into
mainfrom
fix-router-core-lane-match-loader

Conversation

@Sheraff

@Sheraff Sheraff commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Fixes #2980
Fixes #3179
Fixes #4444
Fixes #4572
Fixes #4684
Fixes #4759
Fixes #5106
Fixes #6107
Fixes #6221
Fixes #6351
Fixes #7283
Fixes #7379
Fixes #7602
Fixes #7635
Fixes #7120

Maybe fixes (to verify) #7457

In-scope, but should be fixed already #2182
In-scope, but should be fixed already #2905
In-scope, but should be fixed already #3293
In-scope, but should be fixed already #4476
In-scope, but should be fixed already #4696
In-scope, but should be fixed already #6371
In-scope, but should be fixed already #7110
In-scope, but should be fixed already #7367
In-scope, but should be fixed already #7638

In-scope, but not fixed, maybe we should #5778 (explicitly documented as a known expected failure.)
In-scope, but not fixed, maybe we should #4614 (the old test codifies borrowing the stale committed context; it does not satisfy the issue’s requested fresh preload context.)
In-scope, but not fixed, maybe we should #7633 (its ChunkLoadError test was dropped and isModuleNotFoundError remains unchanged.)
In-scope, but not fixed, maybe we should PR #7673 (not carried over. #7805 deliberately retains the opposite spontaneous-AbortError behavior: success without an error boundary.)

Summary by CodeRabbit

Summary

  • New Features

    • Added a new selective SSR client-only route (/ssr-false-pending-min) and related E2E coverage.
    • Updated the special-characters search page to show “Before load on” (client vs server).
  • Bug Fixes

    • Improved pending UI behavior during redirects, retries, rapid navigations, and invalidations (reducing blank frames and hydration/mismatch issues).
    • Fixed SSR response status codes and hydration handling across pending/error/not-found boundaries.
  • Documentation

    • Clarified client-side preloading behavior for beforeLoad and context reuse rules.

@nx-cloud

nx-cloud Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 2e8bbbe

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

☁️ Nx Cloud last updated this comment at 2026-07-14 00:09:17 UTC

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Changeset Version Preview

No changeset entries found. Merging this PR will not cause a version bump for any packages.

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR replaces legacy router match loading with client/server lane pipelines, shared SSR hydration, simplified stores, updated framework rendering and transition synchronization, targeted HMR refreshes, and extensive regression coverage across router-core, React, Solid, Vue, SSR, and benchmarks.

Changes

Router loading, hydration, and SSR

Layer / File(s) Summary
Client/server loading pipeline
packages/router-core/src/load-client.ts, packages/router-core/src/load-server.ts, packages/router-core/src/router.ts
Adds lane-based loading, loader-flight coordination, failure boundaries, pending sessions, semantic match reuse, cache/resource transfer, and server-result handling.
Stores, routes, chunks, and hydration
packages/router-core/src/stores.ts, packages/router-core/src/route.ts, packages/router-core/src/route-chunks.ts, packages/router-core/src/hydrate.ts
Removes legacy pending/load state, consolidates lazy state, adds route-chunk loading, and introduces shared SSR hydration.
SSR integrations
packages/router-core/src/ssr/*, packages/start-server-core/src/createStartHandler.ts, packages/*-router/src/ssr/*
Sources response statuses and redirect headers from _serverResult and routes hydration through the shared implementation.

Framework adapters and tooling

Layer / File(s) Summary
Framework rendering and transitions
packages/react-router/src/*, packages/solid-router/src/*, packages/vue-router/src/*
Switches pending and boundary rendering to match status/fetch generations, updates render acknowledgements, and removes pending-match context dependencies.
HMR and devtools
packages/router-plugin/src/core/hmr/*, packages/router-plugin/tests/add-hmr/*, packages/router-devtools-core/src/*
Replaces manual HMR match invalidation with targeted route refreshes and derives pending matches from active router state.
Selective SSR coverage
e2e/solid-start/selective-ssr/src/*, e2e/solid-start/selective-ssr/tests/*
Adds an ssr: false pending route and a development hydration regression suite.

Regression coverage

Layer / File(s) Summary
Router-core behavior tests
packages/router-core/tests/*
Covers preload adoption and context reuse, hydration boundaries, resource ownership, abort handling, lazy chunk retries, SSR failures, head projection, not-found selection, and transactional loading.
Framework adapter tests
packages/react-router/tests/*, packages/solid-router/tests/*, packages/vue-router/tests/*
Updates pending, redirect, hydration, navigation, transition, error, and rendered-event assertions for the new pipeline.
Benchmark synchronization
benchmarks/memory/client/scenarios/interrupted-navigations/shared.ts
Removes explicit latestLoadPromise synchronization from the interrupted-navigation workload.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: nlynzaad, schiller-manuel, seancassiere

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.13% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately describes the main router-core lane match loader rewrite.
Linked Issues check ✅ Passed The PR adds core loader/SSR rewrites and targeted tests for the linked router issues, covering pending, redirects, head, hydration, not-found, and preload behavior.
Out of Scope Changes check ✅ Passed The changes are broadly aligned with the router loader/SSR rewrite and its follow-up tests/docs; no clearly unrelated code was introduced.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-router-core-lane-match-loader

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

@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Bundle Size Benchmarks

  • Commit: 884475d55c6c
  • Measured at: 2026-07-13T23:50:43.878Z
  • Baseline source: history:11a6a0d8ba4d
  • Dashboard: bundle-size history
Scenario Current (gzip) Delta vs baseline Initial gzip Raw Brotli Trend
react-router.minimal 87.34 KiB -10 B (-0.01%) 87.20 KiB 271.40 KiB 75.98 KiB ▁▁██████▄▄▄▂
react-router.full 91.01 KiB -53 B (-0.06%) 90.87 KiB 283.29 KiB 79.20 KiB ▅▅██████▅▅▅▁
solid-router.minimal 35.26 KiB -275 B (-0.76%) 35.13 KiB 102.50 KiB 31.85 KiB ▇▇██████▇▇▇▁
solid-router.full 40.27 KiB -315 B (-0.76%) 40.15 KiB 117.57 KiB 36.28 KiB ▇▇██████▇▇▇▁
vue-router.minimal 52.54 KiB -472 B (-0.87%) 52.41 KiB 145.92 KiB 47.28 KiB ▇▇██████▇▇▇▁
vue-router.full 58.49 KiB -458 B (-0.76%) 58.36 KiB 164.68 KiB 52.46 KiB ▇▇██████▇▇▇▁
react-start.minimal 101.82 KiB -166 B (-0.16%) 101.69 KiB 319.34 KiB 88.13 KiB ▅▇██████▇▇▇▁
react-start.deferred-hydration 102.56 KiB -168 B (-0.16%) 101.71 KiB 320.71 KiB 88.84 KiB ▆▇██████▇▇▇▁
react-start.full 105.23 KiB -135 B (-0.13%) 105.09 KiB 329.26 KiB 91.01 KiB ▅▆██████▅▅▅▁
react-start.rsbuild.minimal 99.58 KiB -98 B (-0.10%) 99.41 KiB 313.82 KiB 85.78 KiB ▄▆██████▅▅▅▁
react-start.rsbuild.minimal-iife 99.99 KiB -90 B (-0.09%) 99.83 KiB 314.76 KiB 86.05 KiB ▄▆██████▅▅▅▁
react-start.rsbuild.full 102.83 KiB -64 B (-0.06%) 102.66 KiB 323.88 KiB 88.53 KiB ▄▆██████▄▄▄▁
solid-start.minimal 49.18 KiB -439 B (-0.86%) 49.05 KiB 148.17 KiB 43.46 KiB ▇███████▇▇▇▁
solid-start.deferred-hydration 52.44 KiB -438 B (-0.81%) 49.11 KiB 156.21 KiB 46.40 KiB ▇▇██████▇▇▇▁
solid-start.full 55.01 KiB -421 B (-0.74%) 54.88 KiB 165.07 KiB 48.47 KiB ▇███████▇▇▇▁
vue-start.minimal 70.45 KiB -597 B (-0.82%) 70.32 KiB 202.69 KiB 62.41 KiB ▇███████▇▇▇▁
vue-start.full 74.45 KiB -601 B (-0.78%) 74.32 KiB 215.32 KiB 65.86 KiB ▇███████▇▇▇▁

Current gzip tracks all emitted client JS chunks. Initial gzip tracks only the entry/import graph. Trend sparkline is historical current gzip ending with this PR measurement; lower is better.

@pkg-pr-new

pkg-pr-new Bot commented Jul 13, 2026

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/@tanstack/arktype-adapter@7805

@tanstack/eslint-plugin-router

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

@tanstack/eslint-plugin-start

npm i https://pkg.pr.new/@tanstack/eslint-plugin-start@7805

@tanstack/history

npm i https://pkg.pr.new/@tanstack/history@7805

@tanstack/nitro-v2-vite-plugin

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

@tanstack/react-router

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

@tanstack/react-router-devtools

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

@tanstack/react-router-ssr-query

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

@tanstack/react-start

npm i https://pkg.pr.new/@tanstack/react-start@7805

@tanstack/react-start-client

npm i https://pkg.pr.new/@tanstack/react-start-client@7805

@tanstack/react-start-rsc

npm i https://pkg.pr.new/@tanstack/react-start-rsc@7805

@tanstack/react-start-server

npm i https://pkg.pr.new/@tanstack/react-start-server@7805

@tanstack/router-cli

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

@tanstack/router-core

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

@tanstack/router-devtools

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

@tanstack/router-devtools-core

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

@tanstack/router-generator

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

@tanstack/router-plugin

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

@tanstack/router-ssr-query-core

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

@tanstack/router-utils

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

@tanstack/router-vite-plugin

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

@tanstack/solid-router

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

@tanstack/solid-router-devtools

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

@tanstack/solid-router-ssr-query

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

@tanstack/solid-start

npm i https://pkg.pr.new/@tanstack/solid-start@7805

@tanstack/solid-start-client

npm i https://pkg.pr.new/@tanstack/solid-start-client@7805

@tanstack/solid-start-server

npm i https://pkg.pr.new/@tanstack/solid-start-server@7805

@tanstack/start-client-core

npm i https://pkg.pr.new/@tanstack/start-client-core@7805

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/@tanstack/start-fn-stubs@7805

@tanstack/start-plugin-core

npm i https://pkg.pr.new/@tanstack/start-plugin-core@7805

@tanstack/start-server-core

npm i https://pkg.pr.new/@tanstack/start-server-core@7805

@tanstack/start-static-server-functions

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

@tanstack/start-storage-context

npm i https://pkg.pr.new/@tanstack/start-storage-context@7805

@tanstack/valibot-adapter

npm i https://pkg.pr.new/@tanstack/valibot-adapter@7805

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/@tanstack/virtual-file-routes@7805

@tanstack/vue-router

npm i https://pkg.pr.new/@tanstack/vue-router@7805

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/@tanstack/vue-router-devtools@7805

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/@tanstack/vue-router-ssr-query@7805

@tanstack/vue-start

npm i https://pkg.pr.new/@tanstack/vue-start@7805

@tanstack/vue-start-client

npm i https://pkg.pr.new/@tanstack/vue-start-client@7805

@tanstack/vue-start-server

npm i https://pkg.pr.new/@tanstack/vue-start-server@7805

@tanstack/zod-adapter

npm i https://pkg.pr.new/@tanstack/zod-adapter@7805

commit: 2e8bbbe

@codspeed-hq

codspeed-hq Bot commented Jul 13, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 94 improved benchmarks
❌ 24 regressed benchmarks
✅ 62 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory mem client preload-churn (react) 610 KB 2,482.6 KB -75.43%
Memory mem client preload-churn (solid) 577.3 KB 2,318.2 KB -75.1%
Memory mem client preload-churn (vue) 667.9 KB 2,482.5 KB -73.09%
Memory mem server error-paths not-found (solid) 423.3 KB 964.7 KB -56.13%
Memory mem client unique-location-churn (react) 729 KB 1,241.4 KB -41.27%
Memory mem client navigation-churn (react) 429.2 KB 715.9 KB -40.05%
Memory mem client mount-unmount (react) 510.9 KB 827.8 KB -38.28%
Memory mem server error-paths not-found (vue) 380.7 KB 609.3 KB -37.51%
Memory mem server error-paths unmatched (react) 641.2 KB 972.6 KB -34.07%
Memory mem client unique-location-churn (vue) 1.1 MB 1.5 MB -25.78%
Memory mem client loader-data-retention (vue) 594.9 KB 770.9 KB -22.83%
Memory mem client navigation-churn (vue) 989.2 KB 1,230.6 KB -19.61%
Simulation client-async-pipeline navigation loop (vue) 45.8 ms 53.2 ms -13.8%
Simulation client-rewrites navigation loop (vue) 67.2 ms 75.8 ms -11.34%
Memory mem client unique-location-churn (solid) 841 KB 941.3 KB -10.66%
Memory mem client interrupted-navigations (vue) 870.7 KB 972.4 KB -10.45%
Memory mem server error-paths not-found (react) 266.8 KB 296.4 KB -10.01%
Memory mem server peak-large-page (solid) 756.9 KB 829.1 KB -8.7%
Simulation client-preload interaction loop (vue) 55 ms 58.2 ms -5.51%
Memory mem client navigation-churn (solid) 1.4 MB 1.5 MB -4.88%
... ... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing fix-router-core-lane-match-loader (2e8bbbe) with main (11a6a0d)

Open in CodSpeed

@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.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/vue-router/src/useMatch.tsx (1)

137-154: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Preserve the generic result type instead of erasing it with any.

Vue.computed<any> allows the implementation to violate the declared ThrowOrOptional<UseMatchResult<...>> contract without a compiler error. Type match and result from the existing generic aliases.

As per coding guidelines, “Use TypeScript strict mode with extensive type safety.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/vue-router/src/useMatch.tsx` around lines 137 - 154, Update the
computed result in the useMatch flow to preserve the existing generic result
type instead of using Vue.computed<any>. Type match and result with the existing
generic aliases, including the declared ThrowOrOptional<UseMatchResult<...>>
contract, so incorrect return values are caught by TypeScript while preserving
the current selection and missing-match behavior.

Source: Coding guidelines

🧹 Nitpick comments (7)
e2e/solid-start/selective-ssr/tests/issue-7283-dev-hydration.spec.ts (1)

27-27: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use braces for all conditional bodies.

These one-line if statements violate the repository’s TypeScript control-flow convention.

As per coding guidelines, **/*.{ts,tsx,js,jsx} must use curly braces for control statements.

Also applies to: 79-79, 84-84

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/solid-start/selective-ssr/tests/issue-7283-dev-hydration.spec.ts` at line
27, Update the one-line conditional statements in
issue-7283-dev-hydration.spec.ts, including the checks around lines 27, 79, and
84, to wrap each conditional body in curly braces while preserving their
existing behavior.

Source: Coding guidelines

packages/solid-router/tests/transitioner-remount.test.tsx (1)

54-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid discarding location-state type safety.

Assert the partial state shape directly instead of casting to any.

Proposed change
-    expect((router.state.location.state as any).remounted).toBe(true)
+    expect(router.state.location.state).toMatchObject({ remounted: true })

As per coding guidelines, TypeScript files must use strict mode with extensive type safety.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/solid-router/tests/transitioner-remount.test.tsx` at line 54,
Replace the any cast in the remounted-state assertion with a type-safe assertion
of the partial location-state shape, using an appropriate typed access or
narrowing approach so router.state.location.state remains checked by TypeScript.

Source: Coding guidelines

packages/router-core/tests/fatal-load-rejection.test.ts (1)

25-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Model the error component without bypassing its route contract.

as any prevents this test from detecting changes to the errorComponent interface. Use a callable mock component with its preload property attached, matching the runtime shape used elsewhere.

Proposed fix
+    const ErrorComponent = Object.assign(() => null, {
+      preload: errorComponentPreload,
+    })
+
     const rootRoute = new BaseRootRoute({
       loader: () => 'root data',
-      errorComponent: { preload: errorComponentPreload } as any,
+      errorComponent: ErrorComponent,
     })

As per coding guidelines, TypeScript files must use strict mode with extensive type safety.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/router-core/tests/fatal-load-rejection.test.ts` around lines 25 -
30, Update the errorComponent setup in the BaseRootRoute test to use a typed
callable mock component with its preload property attached, matching the runtime
component shape. Remove the as any cast so TypeScript validates the
errorComponent contract and the test catches interface changes.

Source: Coding guidelines

packages/router-core/tests/issue-6371-search-default-normalization-abort.test.ts (1)

60-75: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep the canonical replacement setup type-checked.

Both as any casts allow this regression test to keep compiling if buildLocation or commitLocation changes incompatibly. Please use their declared/internal option types or a typed helper for the Transitioner operation being reproduced.

As per coding guidelines, TypeScript files must use strict mode with extensive type safety.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/router-core/tests/issue-6371-search-default-normalization-abort.test.ts`
around lines 60 - 75, Remove the as any casts from the buildLocation and
commitLocation calls in this regression test. Use the declared option types or a
typed helper representing the Transitioner operation so both canonical
replacement setup calls remain strictly type-checked while preserving their
existing behavior.

Source: Coding guidelines

packages/router-core/tests/issue-4444-param-parse-error-lazy-child.test.ts (1)

19-21: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert that the lazy child chunk was never requested.

The test can currently pass even if lazyFn runs before the child is trimmed, leaving the documented regression partially uncovered.

Proposed assertion
 expect(
   router.state.matches.find((match) => match.status === 'pending'),
 ).toBeUndefined()
+expect(lazyFn).not.toHaveBeenCalled()
 expect(router.state.isLoading).toBe(false)

Also applies to: 60-68

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/router-core/tests/issue-4444-param-parse-error-lazy-child.test.ts`
around lines 19 - 21, Update the test using the lazyFn mock so it explicitly
asserts lazyFn was never called when the child route is trimmed after the
parameter parse error. Place the assertion after the relevant navigation or
error-handling flow, preserving the existing test behavior while verifying the
lazy child chunk is not requested.
packages/react-router/tests/transactional-loading.test.tsx (1)

130-148: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Capture every committed pair to verify atomic publication.

The final sequential assertions can miss a transient mixed-generation render after childRefresh resolves. Record parent/child values on each committed render and assert that neither parent-v2/child-v1 nor parent-v1/child-v2 occurs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/react-router/tests/transactional-loading.test.tsx` around lines 130
- 148, Update the transactional loading test around the final refresh sequence
to record the parent and child values on every committed render, then assert no
mixed-generation pair occurs: parent-v2 with child-v1 or parent-v1 with
child-v2. Keep the existing final-state assertions and use the
render-observation mechanism already provided by the test setup.
packages/router-core/src/router.ts (1)

1330-1338: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Silent catch {} hides listener failures.

Swallowing all listener exceptions keeps one bad listener from breaking others, but the fully empty catch also hides real bugs during development. Consider logging in non-production.

♻️ Suggested dev logging
       if (listener.eventType === routerEvent.type) {
         try {
           listener.fn(routerEvent)
-        } catch {}
+        } catch (err) {
+          if (process.env.NODE_ENV !== 'production') {
+            console.error(
+              `Error in router event listener for "${routerEvent.type}":`,
+              err,
+            )
+          }
+        }
       }

If tests assert fully-silent behavior, feel free to disregard.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/router-core/src/router.ts` around lines 1330 - 1338, Update the
catch block in the emit method to retain listener isolation while reporting
listener exceptions in non-production environments. Preserve the existing
behavior of continuing to notify other subscribers and keeping production
logging silent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@e2e/solid-start/selective-ssr/src/routes/ssr-false-pending-min.tsx`:
- Around line 6-13: Update recordEvent to avoid casting window to any by
declaring a local Window augmentation for the __events event buffer, then
initialize and append through window.__events. Preserve the existing server
guard and event shape, including the performance timestamp.

In `@packages/react-router/tests/router.test.tsx`:
- Around line 2463-2467: Update the navigation assertion in the router test to
target the parent route’s specific not-found boundary, using its unique test
identifier or boundary-specific text instead of the broad “Not Found” match;
keep the existing home-page and navigation steps unchanged.

In `@packages/router-core/tests/issue-6221-head-waits-for-loader.test.ts`:
- Line 23: Update the authentication check in the relevant test to wrap the
notFound call inside curly braces, preserving the existing condition and
behavior.

In `@packages/solid-router/src/Transitioner.tsx`:
- Around line 47-65: Move the Solid.onCleanup registration for unsub immediately
after router.history.subscribe(router.load), before the early return in the
Transitioner setup. Keep the existing cleanup callback unchanged and remove the
later registration so every execution path disposes the history subscription.

In `@packages/solid-router/tests/on-rendered-change-info.test.tsx`:
- Around line 44-61: Update the onRendered transition handling to call
getLocationChangeInfo with the previously rendered location as the first
argument and the latest resolved location as the second. Ensure fromLocation,
toLocation, and change flags reflect the actual transition, including same-href
state changes; locate the change in the code that constructs the onRendered
event.

In `@packages/vue-router/tests/pending-fallback-promise-replacement.test.tsx`:
- Around line 13-18: Update the afterEach cleanup hook to drain and await all
testCleanups while fake timers remain active, then restore real timers in a
finally block so timer state is reset even if cleanup fails. Preserve the
existing cleanup() call after the callbacks settle.

---

Outside diff comments:
In `@packages/vue-router/src/useMatch.tsx`:
- Around line 137-154: Update the computed result in the useMatch flow to
preserve the existing generic result type instead of using Vue.computed<any>.
Type match and result with the existing generic aliases, including the declared
ThrowOrOptional<UseMatchResult<...>> contract, so incorrect return values are
caught by TypeScript while preserving the current selection and missing-match
behavior.

---

Nitpick comments:
In `@e2e/solid-start/selective-ssr/tests/issue-7283-dev-hydration.spec.ts`:
- Line 27: Update the one-line conditional statements in
issue-7283-dev-hydration.spec.ts, including the checks around lines 27, 79, and
84, to wrap each conditional body in curly braces while preserving their
existing behavior.

In `@packages/react-router/tests/transactional-loading.test.tsx`:
- Around line 130-148: Update the transactional loading test around the final
refresh sequence to record the parent and child values on every committed
render, then assert no mixed-generation pair occurs: parent-v2 with child-v1 or
parent-v1 with child-v2. Keep the existing final-state assertions and use the
render-observation mechanism already provided by the test setup.

In `@packages/router-core/src/router.ts`:
- Around line 1330-1338: Update the catch block in the emit method to retain
listener isolation while reporting listener exceptions in non-production
environments. Preserve the existing behavior of continuing to notify other
subscribers and keeping production logging silent.

In `@packages/router-core/tests/fatal-load-rejection.test.ts`:
- Around line 25-30: Update the errorComponent setup in the BaseRootRoute test
to use a typed callable mock component with its preload property attached,
matching the runtime component shape. Remove the as any cast so TypeScript
validates the errorComponent contract and the test catches interface changes.

In `@packages/router-core/tests/issue-4444-param-parse-error-lazy-child.test.ts`:
- Around line 19-21: Update the test using the lazyFn mock so it explicitly
asserts lazyFn was never called when the child route is trimmed after the
parameter parse error. Place the assertion after the relevant navigation or
error-handling flow, preserving the existing test behavior while verifying the
lazy child chunk is not requested.

In
`@packages/router-core/tests/issue-6371-search-default-normalization-abort.test.ts`:
- Around line 60-75: Remove the as any casts from the buildLocation and
commitLocation calls in this regression test. Use the declared option types or a
typed helper representing the Transitioner operation so both canonical
replacement setup calls remain strictly type-checked while preserving their
existing behavior.

In `@packages/solid-router/tests/transitioner-remount.test.tsx`:
- Line 54: Replace the any cast in the remounted-state assertion with a
type-safe assertion of the partial location-state shape, using an appropriate
typed access or narrowing approach so router.state.location.state remains
checked by TypeScript.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9eff563-1e9d-4b5e-9e0d-17c99dcf056c

📥 Commits

Reviewing files that changed from the base of the PR and between 41f7bf3 and ceaa4d2.

📒 Files selected for processing (162)
  • benchmarks/memory/client/scenarios/interrupted-navigations/shared.ts
  • e2e/solid-start/selective-ssr/src/routeTree.gen.ts
  • e2e/solid-start/selective-ssr/src/routes/ssr-false-pending-min.tsx
  • e2e/solid-start/selective-ssr/tests/issue-7283-dev-hydration.spec.ts
  • packages/react-router/src/Match.tsx
  • packages/react-router/src/Matches.tsx
  • packages/react-router/src/Transitioner.tsx
  • packages/react-router/src/lazyRouteComponent.tsx
  • packages/react-router/src/ssr/renderRouterToStream.tsx
  • packages/react-router/src/ssr/renderRouterToString.tsx
  • packages/react-router/tests/Matches.test.tsx
  • packages/react-router/tests/ancestor-loader-child-pending-min.test.tsx
  • packages/react-router/tests/component-preload-retry-pending-min.test.tsx
  • packages/react-router/tests/component-preload-retry.test.tsx
  • packages/react-router/tests/errorComponent.test.tsx
  • packages/react-router/tests/hydration-capped-boundary-pending.test.tsx
  • packages/react-router/tests/hydration-terminal-lane.test.tsx
  • packages/react-router/tests/issue-4759-pending-frame.test.tsx
  • packages/react-router/tests/issue-7051-force-pending-suspense.test.tsx
  • packages/react-router/tests/issue-7367-pending-min-redirect.test.tsx
  • packages/react-router/tests/issue-7457-redirect-chain-first-load.test.tsx
  • packages/react-router/tests/issue-7638-invalidate-transition-error.test.tsx
  • packages/react-router/tests/loaders.test.tsx
  • packages/react-router/tests/on-rendered-same-href-state.test.tsx
  • packages/react-router/tests/pending-fallback-promise-replacement.test.tsx
  • packages/react-router/tests/preloaded-mount-resolution.test.tsx
  • packages/react-router/tests/redirect.test.tsx
  • packages/react-router/tests/root-pending-min.test.tsx
  • packages/react-router/tests/router.test.tsx
  • packages/react-router/tests/store-updates-during-navigation.test.tsx
  • packages/react-router/tests/transactional-loading.test.tsx
  • packages/react-router/tests/transitioner-listener-errors.test.tsx
  • packages/react-router/tests/transitioner-render-ack.test.tsx
  • packages/react-router/tests/transitioner-router-swap.test.tsx
  • packages/react-router/tests/useNavigate.test.tsx
  • packages/router-core/src/Matches.ts
  • packages/router-core/src/hydrate.ts
  • packages/router-core/src/isServer/client.ts
  • packages/router-core/src/isServer/development.ts
  • packages/router-core/src/isServer/server.ts
  • packages/router-core/src/load-matches.ts
  • packages/router-core/src/load.client.ts
  • packages/router-core/src/load.server.ts
  • packages/router-core/src/redirect.ts
  • packages/router-core/src/route-chunks.ts
  • packages/router-core/src/route.ts
  • packages/router-core/src/router.ts
  • packages/router-core/src/ssr/createRequestHandler.ts
  • packages/router-core/src/ssr/ssr-client.ts
  • packages/router-core/src/ssr/ssr-server.ts
  • packages/router-core/src/stores.ts
  • packages/router-core/tests/background-assets-stale.test.ts
  • packages/router-core/tests/background-trim-abort.test.ts
  • packages/router-core/tests/blocked-navigation-current-load.test.ts
  • packages/router-core/tests/boundary-component-chunk.test.ts
  • packages/router-core/tests/callbacks.test.ts
  • packages/router-core/tests/chunk-failure-lifecycle.test.ts
  • packages/router-core/tests/client-lane-adversarial.test.ts
  • packages/router-core/tests/fatal-load-rejection.test.ts
  • packages/router-core/tests/granular-stores.test.ts
  • packages/router-core/tests/hydrate.test.ts
  • packages/router-core/tests/hydrated-stay-match-data.test.ts
  • packages/router-core/tests/hydration-asset-context-order.test.ts
  • packages/router-core/tests/hydration-boundary-chunks.test.ts
  • packages/router-core/tests/hydration-currentness.test.ts
  • packages/router-core/tests/invalidate-pre-rematch-failure.test.ts
  • packages/router-core/tests/issue-3928-rapid-reload-abort.test.ts
  • packages/router-core/tests/issue-4078-loader-notfound-root-boundary.test.ts
  • packages/router-core/tests/issue-4444-param-parse-error-lazy-child.test.ts
  • packages/router-core/tests/issue-4476-preload-navigate-abort.test.ts
  • packages/router-core/tests/issue-4572-preload-root-beforeload-flags.test.ts
  • packages/router-core/tests/issue-4684-head-on-beforeload-error.test.ts
  • packages/router-core/tests/issue-5106-hydrated-notfound-boundary.test.ts
  • packages/router-core/tests/issue-6107-preload-chunk-failure.test.ts
  • packages/router-core/tests/issue-6221-head-waits-for-loader.test.ts
  • packages/router-core/tests/issue-6351-fuzzy-notfound-layout.test.ts
  • packages/router-core/tests/issue-6371-search-default-normalization-abort.test.ts
  • packages/router-core/tests/issue-7379-head-matches-direct-load.test.ts
  • packages/router-core/tests/issue-7635-dehydrated-error-child-head.test.ts
  • packages/router-core/tests/load-route-chunk.test.ts
  • packages/router-core/tests/load.test.ts
  • packages/router-core/tests/preflight-reentrant-context.test.ts
  • packages/router-core/tests/preload-adoption.test.ts
  • packages/router-core/tests/preload-background-parent-coherence.test.ts
  • packages/router-core/tests/preload-public-cache-behavior.test.ts
  • packages/router-core/tests/preload-public-signal-lifetime.test.ts
  • packages/router-core/tests/routerTestUtils.ts
  • packages/router-core/tests/serial-failure-foreground-prefix.test.ts
  • packages/router-core/tests/server-async-headers-decorative-hang.test.ts
  • packages/router-core/tests/server-beforeload-preload-flag.test.ts
  • packages/router-core/tests/server-chunk-failure-lifecycle.test.ts
  • packages/router-core/tests/server-concurrent-error-notfound.test.ts
  • packages/router-core/tests/server-headers-asset-failure.test.ts
  • packages/router-core/tests/server-loader-abort-error.test.ts
  • packages/router-core/tests/server-serial-ssr-notfound.test.ts
  • packages/router-core/tests/server-ssr-false-assets.test.ts
  • packages/router-core/tests/server-ssr-option-error.test.ts
  • packages/router-core/tests/stay-match-abort.test.ts
  • packages/router-core/tests/superseded-load-await.test.ts
  • packages/router-devtools-core/src/AgeTicker.tsx
  • packages/router-devtools-core/src/BaseTanStackRouterDevtoolsPanel.tsx
  • packages/router-plugin/src/core/hmr/handle-route-update.ts
  • packages/router-plugin/tests/add-hmr.test.ts
  • packages/router-plugin/tests/add-hmr/snapshots/react/arrow-function@true.tsx
  • packages/router-plugin/tests/add-hmr/snapshots/react/arrow-function@webpack-hot.tsx
  • packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute-inline-component@true.tsx
  • packages/router-plugin/tests/add-hmr/snapshots/react/createRootRoute@true.tsx
  • packages/router-plugin/tests/add-hmr/snapshots/react/createRootRouteWithContext-type-args@true.tsx
  • packages/router-plugin/tests/add-hmr/snapshots/react/explicit-undefined-component@true.tsx
  • packages/router-plugin/tests/add-hmr/snapshots/react/function-declaration@true.tsx
  • packages/router-plugin/tests/add-hmr/snapshots/react/multi-component@true.tsx
  • packages/router-plugin/tests/add-hmr/snapshots/react/string-literal-keys@true.tsx
  • packages/router-plugin/tests/add-hmr/snapshots/solid/arrow-function@true.tsx
  • packages/router-plugin/tests/handle-route-update.test.ts
  • packages/solid-router/src/ClientOnly.tsx
  • packages/solid-router/src/Match.tsx
  • packages/solid-router/src/Matches.tsx
  • packages/solid-router/src/Transitioner.tsx
  • packages/solid-router/src/lazyRouteComponent.tsx
  • packages/solid-router/src/matchContext.tsx
  • packages/solid-router/src/routerStores.ts
  • packages/solid-router/src/ssr/renderRouterToStream.tsx
  • packages/solid-router/src/ssr/renderRouterToString.tsx
  • packages/solid-router/src/useMatch.tsx
  • packages/solid-router/tests/Transitioner.test.tsx
  • packages/solid-router/tests/component-preload-retry.test.tsx
  • packages/solid-router/tests/link.test.tsx
  • packages/solid-router/tests/loaders.test.tsx
  • packages/solid-router/tests/on-rendered-change-info.test.tsx
  • packages/solid-router/tests/pending-fallback-promise-replacement.test.tsx
  • packages/solid-router/tests/redirect.test.tsx
  • packages/solid-router/tests/router.test.tsx
  • packages/solid-router/tests/same-route-pending-blank.test.tsx
  • packages/solid-router/tests/server/errorComponent.test.tsx
  • packages/solid-router/tests/store-updates-during-navigation.test.tsx
  • packages/solid-router/tests/transitioner-listener-errors.test.tsx
  • packages/solid-router/tests/transitioner-remount.test.tsx
  • packages/solid-router/tests/transitioner-render-ack.test.tsx
  • packages/solid-router/tests/use-match-outgoing-transition.test.tsx
  • packages/start-server-core/src/createStartHandler.ts
  • packages/vue-router/src/Match.tsx
  • packages/vue-router/src/Matches.tsx
  • packages/vue-router/src/Transitioner.tsx
  • packages/vue-router/src/lazyRouteComponent.tsx
  • packages/vue-router/src/matchContext.tsx
  • packages/vue-router/src/routerStores.ts
  • packages/vue-router/src/ssr/renderRouterToStream.tsx
  • packages/vue-router/src/ssr/renderRouterToString.tsx
  • packages/vue-router/src/useMatch.tsx
  • packages/vue-router/tests/Matches.test.tsx
  • packages/vue-router/tests/Transitioner.test.tsx
  • packages/vue-router/tests/component-preload-retry.test.tsx
  • packages/vue-router/tests/hydration-capped-boundary-pending.test.tsx
  • packages/vue-router/tests/link.test.tsx
  • packages/vue-router/tests/loaders.test.tsx
  • packages/vue-router/tests/pending-fallback-promise-replacement.test.tsx
  • packages/vue-router/tests/redirect.test.tsx
  • packages/vue-router/tests/router.test.tsx
  • packages/vue-router/tests/store-updates-during-navigation.test.tsx
  • packages/vue-router/tests/transitioner-idle-after-render.test.tsx
  • packages/vue-router/tests/transitioner-listener-errors.test.tsx
  • packages/vue-router/tests/transitioner-remount-rendered.test.tsx
💤 Files with no reviewable changes (13)
  • packages/router-plugin/tests/add-hmr.test.ts
  • packages/solid-router/src/matchContext.tsx
  • packages/router-core/src/load-matches.ts
  • packages/solid-router/tests/server/errorComponent.test.tsx
  • packages/solid-router/tests/Transitioner.test.tsx
  • packages/router-core/src/redirect.ts
  • packages/vue-router/src/routerStores.ts
  • packages/router-core/src/ssr/ssr-server.ts
  • packages/solid-router/src/routerStores.ts
  • packages/router-core/tests/callbacks.test.ts
  • packages/vue-router/tests/redirect.test.tsx
  • packages/solid-router/tests/redirect.test.tsx
  • benchmarks/memory/client/scenarios/interrupted-navigations/shared.ts

Comment on lines +6 to +13
function recordEvent(type: string) {
if (typeof window === 'undefined') {
return
}

const global = window as any
global.__events ??= []
global.__events.push({ type, t: performance.now() })

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- target file ---'
cat -n e2e/solid-start/selective-ssr/src/routes/ssr-false-pending-min.tsx

echo '--- search __events ---'
rg -n "__events|recordEvent|interface Window|declare global" e2e/solid-start/selective-ssr/src/routes -S

echo '--- search repo-wide Window augmentation ---'
rg -n "interface Window|declare global" -S .

Repository: TanStack/router

Length of output: 4375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,80p' e2e/solid-start/selective-ssr/src/routes/ssr-false-pending-min.tsx | cat -n

printf '\n--- related typings ---\n'
rg -n "window\\.__(events|events)|__events|interface Window|declare global" -S e2e/solid-start/selective-ssr src . \
  --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**'

Repository: TanStack/router

Length of output: 3954


Type the event buffer instead of casting window to any. window as any bypasses strict TS here; add a local Window augmentation for __events and push through window.__events.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/solid-start/selective-ssr/src/routes/ssr-false-pending-min.tsx` around
lines 6 - 13, Update recordEvent to avoid casting window to any by declaring a
local Window augmentation for the __events event buffer, then initialize and
append through window.__events. Preserve the existing server guard and event
shape, including the performance timestamp.

Source: Coding guidelines

Comment thread packages/react-router/tests/router.test.tsx Outdated
Comment thread packages/router-core/tests/issue-6221-head-waits-for-loader.test.ts
Comment thread packages/solid-router/src/Transitioner.tsx Outdated
Comment on lines +44 to +61
const event = onRendered.mock.calls[0]![0]
expect(event.fromLocation?.pathname).toBe('/')
expect(event.toLocation.pathname).toBe('/next')
expect(event.pathChanged).toBe(true)
expect(event.hrefChanged).toBe(true)

await router.navigate({
to: '/next',
state: { sameHrefState: true } as any,
})
await waitFor(() => expect(onRendered).toHaveBeenCalledTimes(2))

const stateEvent = onRendered.mock.calls[1]![0]
expect(stateEvent.fromLocation?.state.sameHrefState).toBeUndefined()
expect(stateEvent.toLocation.state.sameHrefState).toBe(true)
expect(stateEvent.fromLocation?.href).toBe('/next')
expect(stateEvent.toLocation.href).toBe('/next')
expect(stateEvent.hrefChanged).toBe(false)

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
file="$(fd -a '^Transitioner\.tsx$' packages/solid-router/src | head -n1)"
ast-grep outline "$file" --items all --match 'Transitioner'
rg -n -C5 '\bonRendered\b|getLocationChangeInfo\s*\(' "$file"

Repository: TanStack/router

Length of output: 648


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant files first, then inspect the helper and its call sites.
ast-grep outline packages/solid-router/src/Transitioner.tsx --view expanded
ast-grep outline packages/solid-router/src --view expanded | sed -n '1,220p'

rg -n -C 4 'getLocationChangeInfo|type: .onRendered.|latestLocation|previous.*location|rendered' packages/solid-router/src packages/solid-router/tests

Repository: TanStack/router

Length of output: 38858


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the helper implementation and nearby tests/usages that define its semantics.
rg -n -C 6 'export function getLocationChangeInfo|function getLocationChangeInfo|getLocationChangeInfo\(' packages -g '!**/dist/**' -g '!**/build/**'

# If the implementation lives in router-core, map that file before reading it.
helper_file="$(rg -l 'function getLocationChangeInfo|export function getLocationChangeInfo' packages -g '!**/dist/**' -g '!**/build/**' | head -n1 || true)"
if [ -n "${helper_file:-}" ]; then
  wc -l "$helper_file"
  cat -n "$helper_file" | sed -n '1,240p'
fi

Repository: TanStack/router

Length of output: 16905


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the helper definition and the onRendered event shape to resolve the semantics.
sed -n '918,955p' packages/router-core/src/router.ts
rg -n -C 4 "onRendered|LocationChangeInfo|fromLocation|toLocation|pathChanged|hrefChanged" packages/router-core/src/router.ts packages/solid-router/tests/on-rendered-change-info.test.tsx packages/solid-router/src/Transitioner.tsx

Repository: TanStack/router

Length of output: 16395


Pass the latest location into getLocationChangeInfo
onRendered should report the transition from the previously rendered location to the new one. getLocationChangeInfo(resolvedLocation, resolvedLocation) makes both sides identical, so fromLocation/toLocation and the change flags no longer match the expected event shape.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/solid-router/tests/on-rendered-change-info.test.tsx` around lines 44
- 61, Update the onRendered transition handling to call getLocationChangeInfo
with the previously rendered location as the first argument and the latest
resolved location as the second. Ensure fromLocation, toLocation, and change
flags reflect the actual transition, including same-href state changes; locate
the change in the code that constructs the onRendered event.

@github-actions github-actions Bot added the documentation Everything documentation related label Jul 13, 2026

@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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/router-core/tests/preload-beforeload-reuse.test.ts (1)

222-280: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a same-route loaderDeps case. This test only changes the parent match; it doesn’t cover reusing preloaded child context when the route’s own deps change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/router-core/tests/preload-beforeload-reuse.test.ts` around lines 222
- 280, Extend the test around childBeforeLoad to add a same-route loaderDeps
scenario where the child route’s own dependencies change between preload and
navigation. Configure childRoute with loaderDeps and assert the preloaded child
context is not reused, including updated context values and the expected preload
flags.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/router-core/tests/preload-beforeload-reuse.test.ts`:
- Around line 242-245: Update the regression case around loaderDeps and context
to preserve type checking for the version contract: add a typed validateSearch
definition for version, replace Record<string, any> with the inferred or
explicit validated search type, and remove the as any casts around preloadRoute,
navigate, and beforeLoad replacement by using typed route refresh helpers or a
type-compatible mock.

---

Nitpick comments:
In `@packages/router-core/tests/preload-beforeload-reuse.test.ts`:
- Around line 222-280: Extend the test around childBeforeLoad to add a
same-route loaderDeps scenario where the child route’s own dependencies change
between preload and navigation. Configure childRoute with loaderDeps and assert
the preloaded child context is not reused, including updated context values and
the expected preload flags.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: beb16cf3-124d-4a1b-ae41-86535af7b3c1

📥 Commits

Reviewing files that changed from the base of the PR and between adf73dd and 6f75f50.

📒 Files selected for processing (3)
  • docs/router/guide/preloading.md
  • packages/router-core/src/load-client.ts
  • packages/router-core/tests/preload-beforeload-reuse.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/router-core/src/load-client.ts

Comment on lines +242 to +245
loaderDeps: ({ search }: { search: Record<string, any> }) => ({
version: Number(search.version),
}),
context: ({ deps }: { deps: { version: number } }) => ({

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file='packages/router-core/tests/preload-beforeload-reuse.test.ts'

# Locate all explicit any escapes in this test.
ast-grep run --pattern '$EXPR as any' --lang typescript "$file"
rg -n '\bany\b' "$file"

# Find established typed search-validation patterns in adjacent tests.
rg -n -C8 --type ts 'validateSearch:|loaderDeps:' packages/router-core/tests

Repository: TanStack/router

Length of output: 40432


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file='packages/router-core/tests/preload-beforeload-reuse.test.ts'

# Read the relevant sections around the flagged lines.
sed -n '220,380p' "$file"

# Look for local helpers or typed fixtures used in this file.
rg -n -C4 'createTestRouter|as any|validateSearch|loaderDeps|beforeLoad|preloadRoute|navigate' "$file"

Repository: TanStack/router

Length of output: 21621


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find typed route-option replacement patterns and search validation in nearby tests.
rg -n -C3 '_refreshRoute|options\.beforeLoad\s*=|validateSearch:' packages/router-core/tests/*.test.ts packages/router-core/tests/*.test-d.ts

# Inspect the router test utilities for any helper that already handles route refreshes or typed route replacement.
ast-grep outline packages/router-core/tests/routerTestUtils.ts --view expanded
sed -n '1,260p' packages/router-core/tests/routerTestUtils.ts

Repository: TanStack/router

Length of output: 16839


Keep this regression case type-checked. Record<string, any> and the as any casts around preloadRoute/navigate and beforeLoad replacement bypass the version contract. Add a typed validateSearch for version, then use typed route refresh helpers or assign a type-compatible mock directly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/router-core/tests/preload-beforeload-reuse.test.ts` around lines 242
- 245, Update the regression case around loaderDeps and context to preserve type
checking for the version contract: add a typed validateSearch definition for
version, replace Record<string, any> with the inferred or explicit validated
search type, and remove the as any casts around preloadRoute, navigate, and
beforeLoad replacement by using typed route refresh helpers or a type-compatible
mock.

Source: Coding guidelines

@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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/router-core/tests/hydration-currentness.test.ts`:
- Around line 205-232: Extract the repeated mockWindow.$_TSR scaffolding in the
hydration currentness tests into a helper such as mockDehydratedRouter,
accepting only the matches array and preserving the shared manifest,
dehydratedData, callbacks, buffer, and initialized values. Replace the
duplicated setups at the referenced test blocks with this helper while keeping
each test’s matches payload unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dae5e328-1744-4525-a06b-e2022da66f47

📥 Commits

Reviewing files that changed from the base of the PR and between 6f75f50 and f4b8934.

📒 Files selected for processing (10)
  • e2e/react-start/basic/src/routes/specialChars/search.tsx
  • e2e/react-start/basic/tests/special-characters.spec.ts
  • packages/react-router/src/Transitioner.tsx
  • packages/router-core/src/load-client.ts
  • packages/router-core/src/router.ts
  • packages/router-core/tests/hydrated-stay-match-data.test.ts
  • packages/router-core/tests/hydration-currentness.test.ts
  • packages/solid-router/src/Transitioner.tsx
  • packages/solid-router/tests/transitioner-render-ack.test.tsx
  • packages/vue-router/src/Transitioner.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/solid-router/tests/transitioner-render-ack.test.tsx
  • packages/react-router/src/Transitioner.tsx
  • packages/router-core/tests/hydrated-stay-match-data.test.ts
  • packages/solid-router/src/Transitioner.tsx
  • packages/vue-router/src/Transitioner.tsx
  • packages/router-core/src/load-client.ts
  • packages/router-core/src/router.ts

Comment on lines +205 to +232
mockWindow.$_TSR = {
router: {
manifest: testManifest,
dehydratedData: {},
matches: [
{
i: oldMatches[0]!.id,
s: 'success',
ssr: true,
u: Date.now(),
},
{
i: oldMatches[1]!.id,
s: 'success',
ssr: 'data-only',
b: { source: 'old-server' },
l: 'old-server',
u: Date.now(),
},
],
},
h: vi.fn(),
e: vi.fn(),
c: vi.fn(),
p: vi.fn(),
buffer: [],
initialized: false,
}

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.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Duplicate mockWindow.$_TSR scaffolding across tests.

Each test rebuilds an almost identical { router: { manifest, dehydratedData, matches: [...] }, h, e, c, p, buffer, initialized } shell, differing only in the matches payload. Consider extracting a small helper (e.g. mockDehydratedRouter(matches)) that returns the boilerplate object, taking only the matches array as a parameter, to cut repetition across this (and likely other) tests in the file.

♻️ Example helper extraction
function mockDehydratedRouter(matches: TsrSsrGlobal['router']['matches']) {
  return {
    router: { manifest: testManifest, dehydratedData: {}, matches },
    h: vi.fn(),
    e: vi.fn(),
    c: vi.fn(),
    p: vi.fn(),
    buffer: [],
    initialized: false,
  }
}

Also applies to: 268-295, 325-351, 388-414

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/router-core/tests/hydration-currentness.test.ts` around lines 205 -
232, Extract the repeated mockWindow.$_TSR scaffolding in the hydration
currentness tests into a helper such as mockDehydratedRouter, accepting only the
matches array and preserving the shared manifest, dehydratedData, callbacks,
buffer, and initialized values. Replace the duplicated setups at the referenced
test blocks with this helper while keeping each test’s matches payload
unchanged.

nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

nx-cloud[bot]

This comment was marked as outdated.

@nx-cloud nx-cloud 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.

Important

At least one additional CI pipeline execution has run since the conclusion below was written and it may no longer be applicable.

Nx Cloud has identified a possible root cause for your failed CI:

We identified that this build failure is unrelated to the PR's changes. The tanstack-start-example-rscs example fails because nitro-nightly (a stale October 2025 nightly) attempts to import a ./runtime/meta subpath that is no longer exported by the installed nitro package. This is a pre-existing dependency version incompatibility that needs to be resolved by updating or pinning the nitro-nightly dependency.

No code changes were suggested for this issue.

Trigger a rerun:

Rerun CI

Nx Cloud View detailed reasoning on Nx Cloud ↗


🎓 Learn more about Self-Healing CI on nx.dev

…match-loader

# Conflicts:
#	packages/router-core/tests/issue-4684-head-on-beforeload-error.test.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment