Uh oh!
There was an error while loading. Please reload this page.
perf(router-core): guard default search parser against throws - #7665
perf(router-core): guard default search parser against throws#7665anonrig wants to merge 1 commit into
Conversation
defaultParseSearch ran JSON.parse on every leftover string search value. For plain strings (the common case, e.g. ?q=hello&f=live) JSON.parse throws a SyntaxError that parseSearchWith catches to keep the raw string — and constructing/throwing that error is the dominant cost. Add a couldBeJson guard that decides from the first non-whitespace character whether a value could be valid JSON. It is a superset of JSON's value-start grammar, so any string JSON.parse would accept still gets parsed (identical results); we only skip the guaranteed-throwing parse of non-JSON strings. Search params are parsed on every SSR request and every client navigation. In-situ before/after on defaultParseSearch: ~3.1x faster on mixed X-like queries, ~1.7x on an all-plain-string query.
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds two internal helpers ( ChangesdefaultParseSearch JSON parse guard
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related issues
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 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 |
View your CI Pipeline Execution ↗ for commit b4a3303
☁️ Nx Cloud last updated this comment at |
Merging this PR will degrade performance by 11.83%
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing Footnotes |
There was a problem hiding this comment.
Nx Cloud has identified a possible root cause for your failed CI:
We classified this failure as an environment state issue rather than a code change. The error — a missing resolveRuntimeSuffix export in e2e/e2e-utils/dist/esm/index.js — points to stale or inconsistently built dist artifacts in the e2e test infrastructure, which has no relation to the @tanstack/router-core search param optimization introduced by this PR. Rebuilding the e2e-utils package should restore consistent artifacts and resolve the failure.
No code changes were suggested for this issue.
You can trigger a rerun by pushing an empty commit:
git commit --allow-empty -m "chore: trigger rerun"
git push🎓 Learn more about Self-Healing CI on nx.dev
anonrig
commented
Jun 22, 2026
I'm closing this because Tanstack router repository has a limit of maximum number of pull-request open per a user and it is 6!!!!! |
Sheraff
commented
Jun 22, 2026
I already had a pretty similar PR a while ago https://github.com/TanStack/router/pull/5071/changes not sure why we never merged it. |
What
Stop the default search parser from throwing a
SyntaxErrorfor every plain-string param. Inpackages/router-core/src/searchParams.ts,defaultParseSearchranJSON.parseon every leftover string value:parseMaybeJsonfirst checks, from the first non-whitespace character, whether the value could be JSON and only then callsJSON.parse. The check is a superset of JSON's value-start grammar ({ [ " -0-9t f n, skipping leading whitespace), so any stringJSON.parsewould accept still gets parsed — we only skip the doomed parse of plain strings.Why
qss.decodealready coerces numbers/booleans, soJSON.parseonly ever runs on the remaining string values — which on real apps are mostly plain text (?q=hello&f=live&src=typed_query). Each one throws aSyntaxErrorthatparseSearchWithcatches to keep the raw string, and constructing + throwing that error (with stack capture) is the dominant cost.Search params are parsed on every SSR request and every client navigation. In-situ before/after on the real
defaultParseSearch(Vitestbench):JSON.parse)?q=…&f=live&src=…&pf=1)?q=from:elon since:2024&f=live&…)Correctness
Behavior is identical. The guard never skips a value
JSON.parsewould accept, and for skipped values it returns the raw string — exactly whatparseSearchWithdoes today whenJSON.parsethrows.Verified by:
searchParamssuite (isomorphism round-trips + "alien deserialization" of human-typed params).couldBeJsonis a correct superset ofJSON.parse's accept set.t/f/n-prefixed non-literals (tweet,false_alarm,null_island) stay strings.Notes
defaultStringifySearchuses the sameJSON.parse-as-throw-probe pattern when building URLs (also hot via<Link>), but its logic relies on throw-vs-no-throw as the "is this JSON?" signal, so making it allocation-free cleanly is a slightly larger change — happy to do it as a follow-up.@tanstack/router-corepatch).unused-imports/no-unused-varswarnings on the existingcatch (_err)blocks are untouched by this change.Summary by CodeRabbit