perf(router-core): optimize route tree processing - #7984
Conversation
📝 WalkthroughWalkthroughRoute-tree construction now resolves route-local options, reuses trie nodes, and sorts only newly populated dynamic sibling lists. Matching derives depth from trie nodes. Tests cover route and route-mask specificity, fallback, reuse, case handling, and pathless routes. ChangesRoute tree optimization
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant RouteParser
participant Trie
participant RouteMatcher
RouteParser->>Trie: Build nodes from resolved route paths
Trie-->>RouteParser: Record dynamic sibling lists
RouteParser->>Trie: Sort recorded lists
RouteMatcher->>Trie: Read node depth during matching
Trie-->>RouteMatcher: Return trie-derived specificity
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
🚀 Changeset Version Preview5 package(s) bumped directly, 18 bumped as dependents. 🟩 Patch bumps
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/router-core/src/new-process-route-tree.ts (1)
262-305: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winPass
dynamicListsToSortthroughfindSingleMatch.
parseSegmentsis not exported, butfindSingleMatchcalls it withoutdynamicListsToSort. A single top-level flat route containing two or more sibling dynamic segments can remain unsorted, so matches may pick lower-priority siblings before declaration order is restored.🤖 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/new-process-route-tree.ts` around lines 262 - 305, Update findSingleMatch to accept and pass dynamicListsToSort into its parseSegments call, preserving the existing sorting behavior for sibling dynamic segments in top-level flat routes.
🤖 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/src/new-process-route-tree.ts`:
- Around line 1092-1096: The skipped-bit mask in extractParams is keyed by trie
depth, while buildBranch/nodeIndex consume it by buildBranch order. Align the
producer and consumer by using one consistent key: preferably record skipped
optional nodes in buildBranch order and update nodeIndex accordingly, or change
both sides to depth-based indexing; ensure skipping behavior remains correct
across optional traversal.
---
Outside diff comments:
In `@packages/router-core/src/new-process-route-tree.ts`:
- Around line 262-305: Update findSingleMatch to accept and pass
dynamicListsToSort into its parseSegments call, preserving the existing sorting
behavior for sibling dynamic segments in top-level flat routes.
🪄 Autofix
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 Plus
Run ID: 64521571-feff-4e63-b35e-f9342c940fb2
📒 Files selected for processing (3)
.changeset/faster-route-trees.mdpackages/router-core/src/new-process-route-tree.tspackages/router-core/tests/new-process-route-tree.test.ts
|
View your CI Pipeline Execution ↗ for commit fb90b1e
☁️ Nx Cloud last updated this comment at |
Bundle Size Benchmarks
The following scenarios have bundle-size changes compared with the baseline:
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 0 benchmarks
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | Memory | mem server server-fn-churn (vue) |
4,147.3 KB | 263.1 KB | ×16 |
| ⚡ | Memory | mem server error-paths unmatched (vue) |
2,142.1 KB | 479.4 KB | ×4.5 |
| ⚡ | Memory | mem server peak-large-page (react) |
1,737.5 KB | 953.4 KB | +82.23% |
| ⚡ | Memory | mem server error-paths redirect (solid) |
388 KB | 278.2 KB | +39.49% |
| ⚡ | Memory | mem server error-paths redirect (vue) |
338.6 KB | 293.5 KB | +15.37% |
| ⚡ | Memory | mem server error-paths not-found (react) |
277.7 KB | 255.5 KB | +8.66% |
| ⚡ | Simulation | ssr server-fn multipart (solid) |
64.2 ms | 61.3 ms | +4.64% |
| ⚡ | Simulation | ssr server-fn raw-stream (solid) |
113.2 ms | 108.5 ms | +4.3% |
| ⚡ | Simulation | ssr control-flow unmatched 404 (react) |
58.1 ms | 56.4 ms | +3% |
| 👁 | Memory | mem server error-paths not-found (solid) |
415.1 KB | 789.1 KB | -47.4% |
| 👁 | Simulation | ssr server-fn during document ssr (react) |
62.9 ms | 65.9 ms | -4.62% |
| 👁 | Memory | mem server error-paths redirect (react) |
197 KB | 203.7 KB | -3.31% |
| 👁 | Memory | mem server error-paths unmatched (react) |
317.5 KB | 492.1 KB | -35.49% |
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing codex/consolidate-route-tree-optimizations (fb90b1e) with main (697ebb6)
Summary
@tanstack/router-coreConsolidates
This replaces the overlapping work in:
#7974's fused dynamic-node implementation subsumes #7969's production sorting change; #7969's unique ordering tests are retained.
Runtime performance
Compared with
origin/mainat697ebb6dusing the same focused Vitest benchmark files in separate worktrees:No focused runtime case regressed.
Validation
origin/maingit diff --check, andchangeset statuspassedSummary by CodeRabbit
Performance
Bug Fixes
Tests