Avatar for the withastro user
withastro
astro
BlogDocsChangelog

Performance History

Latest Results

Skip URL normalization writes that would not change the path Assigning `url.pathname` re-parses and re-serializes the whole URL, and costs more than parsing a URL from scratch (~212ns vs ~186ns here). For an ordinary request path such as `/about` the pathname is already decoded and free of duplicate slashes, so both assignments in `normalizeUrl` are no-ops that still pay that cost. Guard each assignment on the value actually changing. Skipping a write whose target already equals the current pathname is by definition a no-op, so behavior is unchanged. Measured on the normalization block: 858ns to 421ns for a plain path. `normalizeUrl` is on the hot path of every SSR request: FetchState calls it to build `state.url`, and `createNormalizedUrl` covers the rewrite path. The collapse has to stay after the decode is written back rather than being folded into it: the pathname setter rewrites `\` to `/`, so a decoded backslash only becomes a duplicate slash once assigned (`/a%5C/b` -> `/a\/b` -> `/a//b` -> `/a/b`). Add unit tests for `normalizeUrl`, which had none, pinning that ordering along with the decode, duplicate-slash and re-encoding cases.
iseraph-dev:perf/normalize-url-guard
4 hours ago
Parse each request URL once by caching it on the request Adapters need a request's URL before handing the request to `match()` and `render()`, and each step parsed the same string over again: a typical SSR request parsed `request.url` three or four times. Add `getRequestURL()`, which parses `request.url` on first use and keeps the result on the request behind a symbol, the same way render options already travel with a request. Export it from `astro/app` so adapters, including community ones, can share the parse instead of each opening with `new URL(request.url)`. This replaces the pre-parsed `URL` that an earlier revision threaded through `RenderOptions` and `match()`. That contract asked callers to pass a URL equal to `new URL(request.url)` and not to reuse it afterwards, and nothing enforced either half. A URL derived from `request.url` on demand cannot disagree with it, since `request.url` is immutable and a rewritten request is a different object. It also needs no signature changes, so `createRequestFromNodeRequest` keeps returning a `Request` and simply hands over the URL it already parsed. FetchState deliberately keeps parsing its own URL: it rewrites `url.pathname`, and `state.url` is handed to user code as `Astro.url`. Cloning the shared URL instead is not an option, because constructing a URL from another URL serializes and re-parses it, and so costs more than parsing `request.url` again. Node needs no adapter change; it benefits from the seeding above. Netlify's SSR function never parsed a URL of its own, so only its cache provider changes.
iseraph-dev:perf/request-url-cache
4 hours ago
Merge branch 'main' into astro-css-fix
thelazylamaGit:astro-css-fix
13 hours ago
changeset: prefetch fetch-fallback rejection
Araluma:fix/prefetch-unhandled-rejection
1 day ago

Latest Branches

CodSpeed Performance Gauge
0%
Skip URL normalization writes that would not change the path#17416
1 day ago
87c8f16
iseraph-dev:perf/normalize-url-guard
CodSpeed Performance Gauge
0%
1 day ago
f7fb775
iseraph-dev:perf/request-url-cache
CodSpeed Performance Gauge
0%
5 hours ago
fc8f235
iseraph-dev:perf/dedupe-route-deserialization
© 2026 CodSpeed Technology
Home Terms Privacy Docs