fix(router-core): isolate client loading lane ownership#7848
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
View your CI Pipeline Execution ↗ for commit 24e3e6a
☁️ Nx Cloud last updated this comment at |
🚀 Changeset Version PreviewNo changeset entries found. Merging this PR will not cause a version bump for any packages. |
Bundle Size Benchmarks
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. |
Merging this PR will regress 12 benchmarks
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ | Memory | mem server error-paths redirect (vue) |
436.7 KB | 693.3 KB | -37.01% |
| ❌ | Simulation | ssr server-fn POST (solid) |
62.8 ms | 72.3 ms | -13.23% |
| ❌ | Simulation | ssr server-fn not-found (solid) |
60.9 ms | 69.5 ms | -12.3% |
| ❌ | Simulation | ssr server-fn send-context (solid) |
64.1 ms | 70.7 ms | -9.28% |
| ❌ | Simulation | ssr server-fn redirect (solid) |
53.5 ms | 57.4 ms | -6.79% |
| ❌ | Simulation | ssr server-fn GET (solid) |
68.4 ms | 73.2 ms | -6.54% |
| ❌ | Memory | mem server streaming-peak chunked (react) |
10.9 MB | 11.6 MB | -5.94% |
| ❌ | Memory | mem client navigation-churn (react) |
714.8 KB | 750.3 KB | -4.73% |
| ❌ | Simulation | ssr dehydrate plain control (react) |
51.4 ms | 53.8 ms | -4.51% |
| ❌ | Memory | mem server error-paths unmatched (react) |
298.4 KB | 311.8 KB | -4.29% |
| ❌ | Memory | mem server error-paths redirect (solid) |
290.6 KB | 301.2 KB | -3.52% |
| ❌ | Memory | mem client interrupted-navigations (solid) |
837.5 KB | 863.6 KB | -3.02% |
| ⚡ | Memory | mem server server-fn-churn (vue) |
4,319.7 KB | 268.3 KB | ×16 |
| ⚡ | Memory | mem server error-paths unmatched (vue) |
2,474.2 KB | 490.3 KB | ×5 |
| ⚡ | Memory | mem server peak-large-page (react) |
2,064.6 KB | 944.3 KB | ×2.2 |
| ⚡ | Memory | mem server peak-large-page (solid) |
946.7 KB | 780 KB | +21.37% |
| ⚡ | Memory | mem server error-paths redirect (react) |
240.7 KB | 224.1 KB | +7.4% |
| ⚡ | Memory | mem client preload-churn (solid) |
2.2 MB | 2.1 MB | +5.27% |
| ⚡ | Memory | mem server error-paths not-found (solid) |
1.1 MB | 1 MB | +4.83% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing opencode/match-loading-review (20906b6) with fix-router-core-lane-match-loader (3d68db6)
Summary
This follow-up makes client loading ownership explicit: foreground transactions, preload lanes, loader flights, background reloads, and HMR no longer borrow authority from one another implicitly. It preserves accepted loader data while preventing stale context, work, and projections from crossing lane boundaries.
Architecture changes and fixed bugs
1. Loader-flight ownership is lane-local
_flightsregistry allowed unrelated navigation, preload, and background lanes to join an individual loader by match id even when their parent generation or complete lane semantics differed. The registry is removed; each loader invocation belongs to one lane, and active sharing happens only through complete-lane adoption.2. Preloads are shared and claimed as complete lanes
_preloadsnow tracks complete lanes; identical concurrent preloads and navigations adopt the whole serial-plus-loader pipeline or run independently.beforeLoadoutput could reuse stale authorization or route context even though only loader data is safe to retain. Completed preloads now clearbeforeLoadcontext before cache publication; navigation reruns context while reusing fresh loader data.preload: falsecould be bypassed by a claim. A navigation could adopt a speculative lane where a required loader had intentionally been skipped. Such lanes are no longer claimable, so navigation performs its blocking load.3. Foreground transaction installation preserves the current writer
_preflightnow guards synchronous planning, while_txremains current until a successfully planned replacement transaction is installed.4. Background reloads publish detached generations
headandscriptshooks ran on objects shared with the committed lane, so a superseded background reload could alter visible metadata even when publication was rejected. Projection now runs on detached, flight-free copies and publishes only while both the owning transaction and exact committed base remain current.fetchCountfor unchanged matches.5. Development route refresh uses the normal transaction protocol
head,scripts, or route-chunk promises never resolve.6. Exact object equality has an explicit mode
undefinedkeys. The default deep-equality behavior treats missing andundefinedkeys as equivalent, which is unsafe for parsed params and search lane identity.deepEqual(a, b, false)now requests exact object keys recursively, including keys whose value isundefined.Documentation
router-core/INTERNALS.mdwith the transaction, lane, lease, cache, background, route-chunk, and HMR ownership protocols.Validation
@tanstack/router-core:test:unit: 93 files, 1,337 passed, 3 expected failures@tanstack/router-core:test:types: TypeScript 5.5 through 6.0@tanstack/router-core:test:eslint: passed with 20 existing warningsreact-router.minimal: gzip 89,443 bytes, matching the base ceilinggit diff --check