Uh oh!
There was an error while loading. Please reload this page.
refactor(router-core): defaultParseSearch,defaultStringifySearch better performance w/ early json exit - #5071
Conversation
WalkthroughUpdates search param parsing/stringifying to avoid unconditional JSON.parse. Introduces an internal looksLikeJson helper. parseSearchWith and stringifySearchWith now apply JSON.parse only to values that appear JSON-like; otherwise, values are passed through or to provided parsers. Public API remains unchanged. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Caller
participant SP as searchParams.ts
participant LLJ as looksLikeJson
participant JP as JSON.parse
Note over SP: parseSearchWith flow (per value)
Caller->>SP: parseSearchWith(value, parser)
SP->>SP: isJsonParser = (parser === JSON.parse)
alt value is string
SP->>LLJ: looksLikeJson(value)
alt isJsonParser AND looksLikeJson
SP->>JP: JSON.parse(value)
JP-->>SP: parsed
SP-->>Caller: parsed
else isJsonParser AND NOT looksLikeJson
SP-->>Caller: value (string as-is)
else not JSON parser
SP->>SP: parser(value)
SP-->>Caller: result
end
else non-string
SP-->>Caller: value (unchanged)
end
sequenceDiagram
autonumber
actor Caller
participant SP as searchParams.ts
participant LLJ as looksLikeJson
participant JP as JSON.parse
Note over SP: stringifySearchWith flow (per value)
Caller->>SP: stringifySearchWith(value, parser)
alt parser exists
alt value is string
SP->>LLJ: looksLikeJson(value)
alt looksLikeJson
SP->>JP: JSON.parse(value)
JP-->>SP: obj
SP->>SP: parser(obj)
SP-->>Caller: string
else not JSON-like
SP-->>Caller: value (string as-is)
end
else non-string
SP->>SP: parser(value)
SP-->>Caller: string
end
else no parser
SP-->>Caller: default handling (unchanged)
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File ( |
View your CI Pipeline Execution ↗ for commit 2d473db
☁️ Nx Cloud last updated this comment at |
There was a problem hiding this comment.
Actionable comments posted: 0
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/searchParams.ts (1)
51-63: Bug: stringify(val) double-quotes JSON-like strings and breaks round-trip typing.When parser succeeds, you’re stringifying the original string instead of the parsed value. Example: "123" becomes ""123"" in the URL, and parses back to the string "123" instead of number 123. Same for "true"/"false". Use stringify(parser(val)).
Apply this diff:
} else if ( hasParser && typeof val === 'string' && (!isJsonParser || looksLikeJson(val)) ) { try { - // Check if it's a valid parseable string.- // If it is, then stringify it again.- parser(val)- return stringify(val)+ // If parseable, canonicalize by stringifying the parsed value.+ const parsed = parser!(val)+ return stringify(parsed) } catch (_err) { // silent } }
🧹 Nitpick comments (3)
packages/router-core/src/searchParams.ts (3)
22-25: Behavior change: strings with leading whitespace won’t be parsed.looksLikeJson checks only the first char. Values like " 123", "\n[1]" are valid JSON for JSON.parse but will now be skipped and remain strings. Confirm this is acceptable, or trim leading whitespace in looksLikeJson (see suggestion below).
77-81: Doc fix: claim about “no false negatives” is inaccurate.Leading whitespace produces false negatives with the current heuristic.
Apply this diff:
/** - * Fast check to see if the string is a likely to be a JSON value.- * It could return false positives (returned true but wasn't actually a json),- * but not false negatives (returned false but was actually a json).+ * Fast, conservative check to see if the string is likely a JSON value.+ * May return false positives (true but not actually JSON) and rare false negatives+ * (e.g. when the string starts with whitespace). */
82-95: Optional: skip leading whitespace in looksLikeJson to avoid false negatives.Small loop; negligible cost, removes a class of surprises.
Apply this diff:
function looksLikeJson(str: string): boolean { - if (!str) return false- const c = str.charCodeAt(0)+ if (!str) return false+ // Skip leading whitespace: space(32), tab(9), lf(10), cr(13)+ let i = 0+ while (i < str.length) {+ const code = str.charCodeAt(i)+ if (code !== 32 && code !== 9 && code !== 10 && code !== 13) break+ i+++ }+ if (i >= str.length) return false+ const c = str.charCodeAt(i) return ( c === 34 || // " c === 123 || // { c === 91 || // [ c === 45 || // - (c >= 48 && c <= 57) || // 0-9 c === 116 || // t (true) c === 102 || // f (false) c === 110 // n (null) ) }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/router-core/src/searchParams.ts(4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Preview
- GitHub Check: Test
🔇 Additional comments (2)
packages/router-core/src/searchParams.ts (2)
11-11: LGTM: caching the JSON.parse identity.Keeps the hot-path branch simple without re-checking inside the loop.
43-43: LGTM: parity with parse path.Mirrors the parse side’s identity check and keeps the conditionals cheap.
…er performance w/ early json exit
5bbf768 to
2d473dbCompare🚀 Changeset Version PreviewNo changeset entries found. Merging this PR will not cause a version bump for any packages. |
Bundle Size Benchmarks
Trend sparkline is historical gzip bytes ending with this PR measurement; lower is better. |
Merging this PR will improve performance by 9.48%
|
| Benchmark | BASE | HEAD | Efficiency | |
|---|---|---|---|---|
| ⚡ | ssr request loop (vue) | 425.9 ms | 409.4 ms | +4.01% |
| ⚡ | ssr request loop (solid) | 153.1 ms | 139.8 ms | +9.48% |
| ⚡ | client-side navigation loop (react) | 55.5 ms | 52.2 ms | +6.45% |
Comparing refactor-router-core-stringify-parse-search-json-perf (2d473db) with main (ed3152a)
Footnotes
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. ↩
LadyBluenotes
commented
Jul 11, 2026
The JSON fast path is still useful, I think, but this branch misses valid JSON values with leading whitespace after URL decoding. The updated implementation and regression coverage are now tracked in #7022, so I’m closing this older version as superseded :) |
Improve performance of
defaultParseSearchanddefaultStringifySearchby skipping callingJSON.parseif we know from the 1 char that it cannot be a valid JSON string.Summary by CodeRabbit