Skip to content

breaking: change preloadCode(pathname) to preloadCode(routeId), make match pre-resolve loaders - #16576

Merged
Rich-Harris merged 8 commits into
version-3from
elliott/preload-code-route-id
Aug 4, 2026
Merged

breaking: change preloadCode(pathname) to preloadCode(routeId), make match pre-resolve loaders#16576
Rich-Harris merged 8 commits into
version-3from
elliott/preload-code-route-id

Conversation

@elliott-with-the-longest-name-on-github

Copy link
Copy Markdown
Contributor

closes #16511

The top-of-the-line goal of this PR is to change preloadCode(pathname) to preloadCode(routeId). This just makes more sense -- the code corresponds to the route you wrote, not the pathname you might be requesting. If you need to resolve a pathname to a route ID, you can always do this:

const route = await match('/foo');
await preloadCode(route.id);

In order to enable this without creating unnecessary waterfalls (where match has to go to the server, and then preloadCode has to go to the server to resolve the route id to its loaders), match caches its resolutions' loaders when it executes.

Basically what this means is that:

  • If serverside route resolution is not enabled
    • match resolution is trivial, because the full routing manifest is available clientside already
  • Else, when routes do resolve on the server, match consults the server for the route definition, then immutably caches the route and its loaders for future reference by preloadCode

There's one additional challenge: When preloadCode is called with a route ID that wasn't resolved using match, it has no cache entry to pull the loaders from. It can't use match internally to resolve the route, because match operates on pathnames and has no ability to resolve a route ID. To enable this, this PR adds an _app/routes/[...id]/__route.js endpoint that operates very similarly to the existing serverside route resolution and allows resolving route IDs to their route info. This enables preloadCode to fall back to actually looking up the information if it hasn't been pre-resolved and cached.

@pkg-svelte-dev

pkg-svelte-dev Bot commented Jul 29, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from 81c34f3:

pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/81c34f3bfb92ae4e89732032a04e60f4f7eb2cc2

Open in pkg.svelte.dev: https://pkg.svelte.dev/repos/kit/pr/16576

@changeset-bot

changeset-bot Bot commented Jul 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 81c34f3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@svelte-docs-bot

Copy link
Copy Markdown

Comment thread packages/kit/src/runtime/server/page/render.js
Comment thread packages/kit/src/runtime/server/page/server_routing.js Outdated
Comment thread packages/kit/src/runtime/server/page/render.js Outdated
Comment thread packages/kit/src/runtime/server/page/server_routing.js
Nic-Polumeyv and others added 4 commits July 30, 2026 10:03
…ing (#16578)

Stacked on #16576, per
#16576 (comment).

`dependencies` is per-`visit()`, so the route-ID module was generated
once per prerendered page. On the `prerendering/basics` fixture with
`resolution: 'server'`, 31 generations produced 28 files; with this, 28
produce 28, and the output is byte-identical apart from the build
version stamp.
* @param {string} app_dir
* @returns {boolean}
*/
export function is_route_id_resolution_path(pathname, base, app_dir) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should import base and app_dir rather than passing them around. Slightly annoying to do on this PR though since this module can be imported from server or client, and we don't have an #app/paths/internal module that points to server/client implementations of a module exposing base and app_dir (we do have $app/paths/internal/(server|client) but that's something slightly different, which in any case should probably be replaced with a subpath import), so I'll add it to the long list of things I want to tidy up at some point

// `client.routes` only contains routes with a `+page`, so a miss above doesn't mean the
// route doesn't exist — it might be a `+server.js`-only route. `_.routes` includes those
// (with `page: null`), so we can distinguish "exists but has no code" from "unknown".
if (manifest._.routes.some((r) => r.id === route_id && !r.page)) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maddening that we need to do two lookups and that manifest._.client.routes is subtly different than manifest._.routes, but that predates this PR, and changing it would be invasive so I'll leave it for another time

Comment thread packages/kit/src/runtime/pathname.js Outdated
@Rich-Harris
Rich-Harris merged commit f70f679 into version-3 Aug 4, 2026
26 checks passed
@Rich-Harris
Rich-Harris deleted the elliott/preload-code-route-id branch August 4, 2026 00:44
Rich-Harris pushed a commit that referenced this pull request Aug 4, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to version-3, this PR
will be updated.

⚠️⚠️⚠️⚠️⚠️⚠️

`version-3` is currently in **pre mode** so this branch has prereleases
rather than normal releases. If you want to exit prereleases, run
`changeset pre exit` on `version-3`.

⚠️⚠️⚠️⚠️⚠️⚠️

# Releases
## @sveltejs/kit@3.0.0-next.14

### Major Changes

- breaking: refresh all load functions/queries when clicking a link to
the current URL ([#16572](#16572))

- breaking: only include routes with a `+page` or `+server` in `RouteId`
([#16580](#16580))

- breaking: require Node 22.17
([#16597](#16597))

- breaking: `preloadCode` now takes a route ID (e.g. `/blog/[slug]`)
instead of a pathname. Route IDs are not prefixed with `paths.base`
([#16576](#16576))

- breaking: remove deprecated `.run()` method from live queries
([#16573](#16573))

### Minor Changes

- feat: return the list of compressed files from `builder.compress`
([#16566](#16566))

- feat: add `page` and `endpoint` booleans to `$app/manifest`'s
`routes`, and export a `ManifestRoute` type
([#16594](#16594))

- feat: add `PageRouteId` and `EndpointRouteId` to `$app/types`
([#16594](#16594))

### Patch Changes

- fix: generate valid `Path` types for routes with optional or rest
params, several params in one segment, or escape sequences
([#16577](#16577))

- fix: decode all numeric character references, including above `ffff`,
when crawling prerendered pages
([#16611](#16611))

- chore: deduplicate request hashing for serialized fetch responses
([#16499](#16499))

- fix: don't treat `Object.prototype` members as param matchers during
validation ([#16612](#16612))

- fix: exclude routes without a page or endpoint from `routes` in
`$app/manifest`, and remove directories with no route files from
`LayoutParams` ([#16588](#16588))

- chore: reuse base64 and text decoding helpers
([#16608](#16608))

- fix: record the mime types of prerendered paths in the server manifest
([#16564](#16564))

- chore: only generate each route's resolution module once when
prerendering ([#16576](#16576))

- fix: expand `[x+nn]` and `[u+nnnn]` escape sequences when resolving a
route id to a pathname
([#16570](#16570))

- fix: allow routes to contain `[` and `]` via the `[x+5b]` and `[x+5d]`
escapes ([#16569](#16569))

- chore: remove the dead `SSRState.fallback` field and name the server
state fork semantics
([#16598](#16598))

- fix: import resolved peer dependencies as file URLs so
project-relative resolution works on Windows
([#16618](#16618))

- fix: write generated tsconfig to `node_modules/$app/tsconfig.json` so
that tools with simplified tsconfig resolution can find it
([#16589](#16589))

- fix: prerender and crawl pages whose `content-type` header carries a
`charset` parameter
([#16567](#16567))

- fix: stream promised `read` results lazily instead of eagerly
buffering them ([#16622](#16622))

- fix: correctly decode `[u+nnnn]` escape sequences above `ffff`
([#16611](#16611))
## @sveltejs/adapter-auto@8.0.0-next.2

### Patch Changes

- fix: convert resolved adapter path to a file URL before importing, so
builds work on Windows
([#16618](#16618))
- Updated dependencies
[[`c3f58bb`](c3f58bb),
[`b655dc7`](b655dc7),
[`a70cc4f`](a70cc4f),
[`b325afb`](b325afb),
[`e76b3d7`](e76b3d7),
[`58f47eb`](58f47eb),
[`fe9d8d9`](fe9d8d9),
[`0c7bbd7`](0c7bbd7),
[`08d7e2a`](08d7e2a),
[`f70f679`](f70f679),
[`0624b26`](0624b26),
[`0624b26`](0624b26),
[`f4222ad`](f4222ad),
[`089628b`](089628b),
[`d8617b3`](d8617b3),
[`c7369a1`](c7369a1),
[`5e5e592`](5e5e592),
[`60057c1`](60057c1),
[`f70f679`](f70f679),
[`38f1528`](38f1528),
[`40092f3`](40092f3),
[`ff4247e`](ff4247e),
[`79a5de5`](79a5de5),
[`a70cc4f`](a70cc4f)]:
  - @sveltejs/kit@3.0.0-next.14
## @sveltejs/adapter-cloudflare@8.0.0-next.4

### Patch Changes

- fix: avoid caching immutable asset 404s
([#16627](#16627))
- Updated dependencies
[[`c3f58bb`](c3f58bb),
[`b655dc7`](b655dc7),
[`a70cc4f`](a70cc4f),
[`b325afb`](b325afb),
[`e76b3d7`](e76b3d7),
[`58f47eb`](58f47eb),
[`fe9d8d9`](fe9d8d9),
[`0c7bbd7`](0c7bbd7),
[`08d7e2a`](08d7e2a),
[`f70f679`](f70f679),
[`0624b26`](0624b26),
[`0624b26`](0624b26),
[`f4222ad`](f4222ad),
[`089628b`](089628b),
[`d8617b3`](d8617b3),
[`c7369a1`](c7369a1),
[`5e5e592`](5e5e592),
[`60057c1`](60057c1),
[`f70f679`](f70f679),
[`38f1528`](38f1528),
[`40092f3`](40092f3),
[`ff4247e`](ff4247e),
[`79a5de5`](79a5de5),
[`a70cc4f`](a70cc4f)]:
  - @sveltejs/kit@3.0.0-next.14
## @sveltejs/adapter-node@6.0.0-next.7

### Patch Changes

- fix: serve static files with the Content-Type recorded in the manifest
([#16564](#16564))

- fix: don't send `Vary: Accept-Encoding` for assets that were never
precompressed ([#16566](#16566))
- Updated dependencies
[[`c3f58bb`](c3f58bb),
[`b655dc7`](b655dc7),
[`a70cc4f`](a70cc4f),
[`b325afb`](b325afb),
[`e76b3d7`](e76b3d7),
[`58f47eb`](58f47eb),
[`fe9d8d9`](fe9d8d9),
[`0c7bbd7`](0c7bbd7),
[`08d7e2a`](08d7e2a),
[`f70f679`](f70f679),
[`0624b26`](0624b26),
[`0624b26`](0624b26),
[`f4222ad`](f4222ad),
[`089628b`](089628b),
[`d8617b3`](d8617b3),
[`c7369a1`](c7369a1),
[`5e5e592`](5e5e592),
[`60057c1`](60057c1),
[`f70f679`](f70f679),
[`38f1528`](38f1528),
[`40092f3`](40092f3),
[`ff4247e`](ff4247e),
[`79a5de5`](79a5de5),
[`a70cc4f`](a70cc4f)]:
  - @sveltejs/kit@3.0.0-next.14
## @sveltejs/adapter-static@4.0.0-next.3

### Patch Changes

- fix: avoid caching immutable asset 404s when configuring for Vercel
([#16626](#16626))
- Updated dependencies
[[`c3f58bb`](c3f58bb),
[`b655dc7`](b655dc7),
[`a70cc4f`](a70cc4f),
[`b325afb`](b325afb),
[`e76b3d7`](e76b3d7),
[`58f47eb`](58f47eb),
[`fe9d8d9`](fe9d8d9),
[`0c7bbd7`](0c7bbd7),
[`08d7e2a`](08d7e2a),
[`f70f679`](f70f679),
[`0624b26`](0624b26),
[`0624b26`](0624b26),
[`f4222ad`](f4222ad),
[`089628b`](089628b),
[`d8617b3`](d8617b3),
[`c7369a1`](c7369a1),
[`5e5e592`](5e5e592),
[`60057c1`](60057c1),
[`f70f679`](f70f679),
[`38f1528`](38f1528),
[`40092f3`](40092f3),
[`ff4247e`](ff4247e),
[`79a5de5`](79a5de5),
[`a70cc4f`](a70cc4f)]:
  - @sveltejs/kit@3.0.0-next.14
## @sveltejs/enhanced-img@1.0.0-next.3

### Patch Changes

- chore: bump `vite-imagetools` to v11
([#16630](#16630))
## @sveltejs/package@3.0.0-next.4

### Patch Changes

- chore: remove dependency on sade
([#16619](#16619))

- fix: import resolved peer dependencies as file URLs so
project-relative resolution works on Windows
([#16618](#16618))

- fix: emit declarations when the tsconfig lives above the package root
([#16568](#16568))

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update preloadCode API

4 participants