From 910909aa7224a6d552b151f8a5a1de4d80df623a Mon Sep 17 00:00:00 2001 From: Zhi Date: Wed, 2 Sep 2026 13:03:30 +0800 Subject: [PATCH] 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 --- packages/fresh/src/router.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/fresh/src/router.ts b/packages/fresh/src/router.ts index c0bbfa9293a..762b175e68d 100644 --- a/packages/fresh/src/router.ts +++ b/packages/fresh/src/router.ts @@ -158,7 +158,14 @@ export class UrlPatternRouter implements Router { for (let i = 0; i < this.#dynamicArr.length; i++) { const route = this.#dynamicArr[i]; - const match = route.pattern.exec(url); + // Pass `url.href` instead of the `URL` object: ~13-21x faster. + // Deno's URLPattern is a pure JS implementation. Given a `URL` object, + // `webidl.converters["URLPatternInput"]` walks and converts its + // properties on every call, and this happens *before* the internal + // match cache is consulted — so the cache never helps. A string skips + // that conversion entirely. `URL` objects cache their serialization, + // so reading `.href` here costs ~3ns. + const match = route.pattern.exec(url.href); if (match === null) continue; result.pattern = route.pattern.pathname;