fix: pass url string to URLPattern.exec() in dynamic route matching - #3901
Open
SisyphusZheng wants to merge 1 commit into
Open
fix: pass url string to URLPattern.exec() in dynamic route matching#3901SisyphusZheng wants to merge 1 commit into
SisyphusZheng wants to merge 1 commit into
Conversation
Deno's URLPattern implementation runs webidl.converters["URLPatternInput"] when exec() receives a URL object. That conversion walks the object's properties on every call and happens before the internal match cache is consulted, so the cache never helps. Passing the serialized url skips the conversion layer entirely and hits the cache directly. Measured with 6 route patterns, median of 5 rounds x 100k calls: - Deno 2.9.0 (aarch64-darwin): 4348 -> 221 ns/call (~19.7x) - Node 24.18.0 (native URLPattern): 2376 -> 1220 ns/call (~1.9x) The win is specific to runtimes with a JS-based URLPattern (Deno); on runtimes with a native implementation there is no regression. Reading url.href costs ~2ns because URL objects cache their serialization. Refs freshframework#1931
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
UrlPatternRouter.match()passes theURLobject directly toroute.pattern.exec(url)in the dynamic route loop:https://github.com/freshframework/fresh/blob/86d6cde/packages/fresh/src/router.ts#L158-L169
Deno's
URLPatternis a pure JS implementation. Whenexec()receives an object,webidl.converters["URLPatternInput"]walks and converts the object's properties on every call — and that conversion happens before the internal match cache is consulted, so the cache never helps. Passing a string skips the conversion layer entirely and hits the cache directly.This is the remaining hot spot of #1931: the static-route
Mapadded back then addressed the static case, but every dynamic-routeexec()call still pays the WebIDL conversion cost.Benchmark
6 route patterns (
/,/about,/blog/:slug,/api/v1/users/:id/posts/:postId,/docs/:path*,/greet/:name), round-robinexec(), median of 5 rounds × 100,000 calls:exec(url)— URL objectexec(url.href)— stringurl.hrefcosts ~2 ns (URL objects cache their serialization), so the switch itself is free.URLPattern(Deno). On runtimes with a native implementation the difference is small but points in the same direction — no regression.benchmark script
Change
One line plus a comment: pass
url.hrefinstead of theURLobject.Semantics
UrlPatternRouteronly compiles{ pathname }patterns — every other component compiles to*— and onlymatch.pathname.groupsis consumed afterwards. For pathname-only patterns,exec(url)andexec(url.href)are equivalent: serializing the URL and re-parsing the string yields exactly the component values the object conversion would read.Verified differentially on Deno 2.9.0 and Node 24.18.0: 10 pathname patterns × 20 URLs (query strings, hashes, percent-encoded paths, mixed-case hosts, ports, userinfo, trailing slashes) = 200 combos per runtime, full match results compared (minus the
inputsfield, which by spec echoes the original input) — 0 mismatches.Testing
deno lint,deno task check:types,deno fmt(changed file): passpackages/fresh/src(205 tests total)Refs #1931
This PR was prepared with AI assistance for benchmarking and analysis; the change itself is the one-liner above.