Skip to content

Commit 910909a

Browse files
committed
fix: pass url string to URLPattern.exec() in dynamic route matching
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 #1931
1 parent 86d6cde commit 910909a

1 file changed

Lines changed: 8 additions & 1 deletion

File tree

‎packages/fresh/src/router.ts‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,14 @@ export class UrlPatternRouter<T> implements Router<T> {
158158
for (let i = 0; i < this.#dynamicArr.length; i++) {
159159
const route = this.#dynamicArr[i];
160160

161-
const match = route.pattern.exec(url);
161+
// Pass `url.href` instead of the `URL` object: ~13-21x faster.
162+
// Deno's URLPattern is a pure JS implementation. Given a `URL` object,
163+
// `webidl.converters["URLPatternInput"]` walks and converts its
164+
// properties on every call, and this happens *before* the internal
165+
// match cache is consulted — so the cache never helps. A string skips
166+
// that conversion entirely. `URL` objects cache their serialization,
167+
// so reading `.href` here costs ~3ns.
168+
const match = route.pattern.exec(url.href);
162169
if (match === null) continue;
163170

164171
result.pattern = route.pattern.pathname;

0 commit comments

Comments
 (0)