Skip to content

optimize path.ts#7463

Open
schiller-manuel wants to merge 1 commit into
mainfrom
perf-path
Open

optimize path.ts#7463
schiller-manuel wants to merge 1 commit into
mainfrom
perf-path

Conversation

@schiller-manuel
Copy link
Copy Markdown
Collaborator

@schiller-manuel schiller-manuel commented May 21, 2026

BEFORE implementation

  • Unit: tests/path.test.ts passed, 369 tests.
  • Perf tests/path.bench.ts:
    • resolvePath mixed uncached: 1,029,673.50 hz, mean 0.0010 ms, p99 0.0014, rme ±0.58%.
    • resolvePath mixed cached: 464,285.90 hz, mean 0.0022 ms, p99 0.0035, rme ±4.59%.
    • interpolatePath mixed client parser: 175,720.33 hz, mean 0.0057 ms, p99 0.0065, rme ±0.29%.
    • interpolatePath server fast path: 727,297.36 hz, mean 0.0014 ms, p99 0.0016, rme ±0.40%.
  • Bundle react-router.minimal: gzip 89214, initial 89073, raw 279460, brotli 77582.

AFTER implementation

  • Unit: tests/path.test.ts passed, 369 tests.
  • Perf tests/path.bench.ts:
    • resolvePath mixed uncached: 1,025,539.62 hz, mean 0.0010 ms, p99 0.0012, rme ±2.89%.
    • resolvePath mixed cached: 457,368.98 hz, mean 0.0022 ms, p99 0.0038, rme ±3.62%.
    • interpolatePath mixed client parser: 174,467.75 hz, mean 0.0057 ms, p99 0.0066, rme ±1.72%.
    • interpolatePath server fast path: 741,271.30 hz, mean 0.0013 ms, p99 0.0015, rme ±0.57%.
  • Bundle react-router.minimal: gzip 89179, initial 89039, raw 279330, brotli 77564.

Comparison notes

  • Bundle diff: gzip -35, initial -34, raw -130, brotli -18.
  • Focused perf is comparable: small hz movements are within observed noise/rme; p99 is flat or improved except cached resolvePath (+0.0003 ms).
  • Full bundle run: every scenario improved gzip (-23 to -51); raw dropped by ~130 bytes in every scenario.

Summary by CodeRabbit

  • Improvements

    • Optimized path resolution and interpolation for more efficient route matching
    • Enhanced trailing slash handling across various URL scenarios
    • Improved preservation of splat parameters with special characters
  • Tests

    • Added benchmark tests for path routing operations
    • Expanded test coverage for edge cases in path resolution and splat handling

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b28ab08b-4a2a-448e-8a29-e99aeeb0b456

📥 Commits

Reviewing files that changed from the base of the PR and between e2896b5 and ecdd3b2.

📒 Files selected for processing (3)
  • packages/router-core/src/path.ts
  • packages/router-core/tests/path.bench.ts
  • packages/router-core/tests/path.test.ts

📝 Walkthrough

Walkthrough

This PR optimizes the TanStack Router path utilities by refactoring path resolution and interpolation logic. Changes include simplified absolute-path detection in resolvePath, expanded character handling in encodeParam splat parameters, substring-to-slice replacements throughout interpolatePath, and early-return short-circuiting for non-interpolated paths. New test coverage validates empty/base destinations and splat character preservation, and a comprehensive benchmark suite measures performance across uncached, cached, client, and server execution paths.

Changes

Path Utilities Performance and Correctness Improvements

Layer / File(s) Summary
resolvePath absolute and base detection
packages/router-core/src/path.ts, packages/router-core/tests/path.test.ts
isAbsolute detection switched from startsWith to direct character check (to[0] === '/'), and isBase now uses explicit dot matching (to === '.'). Segment parsing generalized empty-segment checks from value === '' to !value. Tests cover empty-string and dot-relative destinations with never, always, and preserve trailing-slash modes.
encodeParam splat character expansion
packages/router-core/src/path.ts, packages/router-core/tests/path.test.ts
Early-return optimization regex expanded from alphanumeric/limited-punctuation set to word-character-based pattern (^[-\w.~!/]*$). Tests verify slash preservation in named splat parameters and URL-safe character handling with optional custom decoder functions.
interpolatePath server fast-path and string method refactoring
packages/router-core/src/path.ts
Early-return condition simplified to short-circuit on falsy or non-interpolated paths (path || '/'). Replaced substring with slice throughout server fast-path and general parser (segment extraction, param keys, pathname appending, wildcard prefix/suffix). Trailing-slash detection switched from endsWith to index check. Required-param missing flag now set via explicit presence check before assigning usedParams.
Path utility performance benchmarks
packages/router-core/tests/path.bench.ts
New Vitest benchmark suite with predefined test cases and validation loops. resolvePath benchmarks measure uncached and LRU-cached resolution. interpolatePath benchmarks cover client-side parsing and server fast-path with regular params and _splat handling, consuming results to prevent dead-code elimination.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

package: router-core

Poem

A rabbit hops through paths anew,
With slices swift and branches true,
Where splats encode and fast-paths fly,
The benchmarks measure, speeds run high. ⚡🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title "optimize path.ts" is vague and does not clearly convey the specific optimizations or changes made in the pull request. Consider using a more descriptive title that indicates the specific focus of optimizations, such as "Optimize path resolution and interpolation performance" or "Improve path utility performance via string operation refinements."
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf-path

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

@nx-cloud
Copy link
Copy Markdown
Contributor

nx-cloud Bot commented May 21, 2026

View your CI Pipeline Execution ↗ for commit ecdd3b2

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

☁️ Nx Cloud last updated this comment at 2026-05-21 20:35:21 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 21, 2026

More templates

@tanstack/arktype-adapter

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

@tanstack/eslint-plugin-router

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

@tanstack/eslint-plugin-start

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

@tanstack/history

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

@tanstack/nitro-v2-vite-plugin

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

@tanstack/react-router

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

@tanstack/react-router-devtools

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

@tanstack/react-router-ssr-query

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

@tanstack/react-start

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

@tanstack/react-start-client

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

@tanstack/react-start-rsc

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

@tanstack/react-start-server

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

@tanstack/router-cli

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

@tanstack/router-core

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

@tanstack/router-devtools

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

@tanstack/router-devtools-core

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

@tanstack/router-generator

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

@tanstack/router-plugin

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

@tanstack/router-ssr-query-core

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

@tanstack/router-utils

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

@tanstack/router-vite-plugin

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

@tanstack/solid-router

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

@tanstack/solid-router-devtools

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

@tanstack/solid-router-ssr-query

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

@tanstack/solid-start

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

@tanstack/solid-start-client

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

@tanstack/solid-start-server

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

@tanstack/start-client-core

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

@tanstack/start-fn-stubs

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

@tanstack/start-plugin-core

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

@tanstack/start-server-core

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

@tanstack/start-static-server-functions

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

@tanstack/start-storage-context

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

@tanstack/valibot-adapter

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

@tanstack/virtual-file-routes

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

@tanstack/vue-router

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

@tanstack/vue-router-devtools

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

@tanstack/vue-router-ssr-query

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

@tanstack/vue-start

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

@tanstack/vue-start-client

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

@tanstack/vue-start-server

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

@tanstack/zod-adapter

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

commit: ecdd3b2

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

@github-actions
Copy link
Copy Markdown
Contributor

Bundle Size Benchmarks

  • Commit: 7867f59c5341
  • Measured at: 2026-05-21T20:35:16.029Z
  • Baseline source: history:65b4abe65bc2
  • Dashboard: bundle-size history
Scenario Current (gzip) Delta vs baseline Initial gzip Raw Brotli Trend
react-router.minimal 87.27 KiB -28 B (-0.03%) 87.13 KiB 273.89 KiB 75.92 KiB ███████▄▄▄▄▁
react-router.full 90.79 KiB -30 B (-0.03%) 90.65 KiB 285.38 KiB 78.87 KiB ▇▇▇▇▇▇█▄▄▄▄▁
solid-router.minimal 35.51 KiB -18 B (-0.05%) 35.39 KiB 106.20 KiB 32.02 KiB ▆▆▆████▃▃▃▃▁
solid-router.full 40.24 KiB -34 B (-0.08%) 40.11 KiB 120.40 KiB 36.16 KiB ▇▇▇▇▇▇█████▁
vue-router.minimal 53.29 KiB -35 B (-0.06%) 53.16 KiB 151.33 KiB 47.92 KiB ██████▆▇▇▇▇▁
vue-router.full 58.41 KiB -35 B (-0.06%) 58.28 KiB 167.49 KiB 52.35 KiB ██████▇████▁
react-start.minimal 101.99 KiB -33 B (-0.03%) 101.85 KiB 322.34 KiB 88.34 KiB ▅▅▅▇▇▇▆████▁
react-start.deferred-hydration 103.04 KiB -37 B (-0.04%) 102.16 KiB 323.98 KiB 89.29 KiB ████▇▇▇▇▁
react-start.full 105.39 KiB -31 B (-0.03%) 105.25 KiB 332.66 KiB 91.17 KiB ▇▇▇████▅▅▅▅▁
react-start.rsbuild.minimal 99.61 KiB -24 B (-0.02%) 99.44 KiB 316.80 KiB 85.72 KiB ▇▇▇▇▇▇▆████▁
react-start.rsbuild.full 102.91 KiB -21 B (-0.02%) 102.74 KiB 327.21 KiB 88.46 KiB ██████▇▇▇▇▇▁
solid-start.minimal 49.64 KiB -29 B (-0.06%) 49.51 KiB 152.33 KiB 43.83 KiB ▃▃▃████▆▆▆▆▁
solid-start.deferred-hydration 53.71 KiB -34 B (-0.06%) 50.36 KiB 160.86 KiB 47.68 KiB ███▇▃▃▃▃▁
solid-start.full 55.43 KiB -30 B (-0.05%) 55.30 KiB 169.22 KiB 48.82 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.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 21, 2026

Merging this PR will not alter performance

✅ 5 untouched benchmarks
⏩ 1 skipped benchmark1


Comparing perf-path (ecdd3b2) with main (65b4abe)2

Open in CodSpeed

Footnotes

  1. 1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports.

  2. No successful run was found on main (e2896b5) during the generation of this report, so 65b4abe was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

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.

1 participant