Skip to content

feat: version 3 - #15497

Draft
teemingc wants to merge 681 commits into
mainfrom
version-3
Draft

feat: version 3#15497
teemingc wants to merge 681 commits into
mainfrom
version-3

Conversation

@teemingc

@teemingc teemingc commented Mar 5, 2026

Copy link
Copy Markdown
Member

Opened just so that I could easily see CI checks

You can try SvelteKit 3 by installing any of the packages following #15497 (comment) or the ones published with the next tag https://npmx.dev/package/@sveltejs/kit


Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

Edits

  • Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.

@changeset-bot

changeset-bot Bot commented Mar 5, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8a962cd

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

This PR includes changesets to release 8 packages
Name Type
@sveltejs/kit Major
@sveltejs/adapter-node Patch
@sveltejs/adapter-cloudflare Major
@sveltejs/adapter-vercel Patch
@sveltejs/adapter-auto Patch
@sveltejs/adapter-static Patch
@sveltejs/adapter-netlify Patch
@sveltejs/package Patch

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

@teemingc teemingc added needs-platform-tests This PR needs to run platform tests in order to merge. needs-ecosystem-ci This PR needs to have an ecosystem CI run started prior to its last commit before merging. breaking change labels Mar 5, 2026
@Rich-Harris

Copy link
Copy Markdown
Member

ok, bringing this up to date with main after #15934 etc is proving to be a bit of a PITA but we're getting there. (Unfortunately it also creates conflicts on #15574 — gah.) Logging off now, will pick it up tomorrow. We are at least able to delete quite a bit of stuff now

Comment thread .changeset/shaggy-walls-wave.md Outdated
Comment thread .changeset/tidy-toes-sort.md Outdated
@Rich-Harris Rich-Harris removed the needs-ecosystem-ci This PR needs to have an ecosystem CI run started prior to its last commit before merging. label Jun 4, 2026
@Rich-Harris

Copy link
Copy Markdown
Member

Finally it looks like we have a clean run and can go back to opening PRs against this branch. Will see how much work is involved in fixing the conflicts on #15574

Comment thread packages/kit/src/utils/url.js Fixed
@pkg-svelte-dev

pkg-svelte-dev Bot commented Jul 1, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from 8a962cd:

pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/8a962cd83ed2caf23de92ff9efd6ffef92531326

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

Comment thread packages/kit/src/exports/url.js Fixed
@sveltejs sveltejs deleted a comment from netlify Bot Jul 6, 2026
@teemingc teemingc added needs-platform-tests This PR needs to run platform tests in order to merge. and removed needs-platform-tests This PR needs to run platform tests in order to merge. labels Jul 7, 2026
Nic-Polumeyv and others added 10 commits July 22, 2026 13:07
…error page (#16381)

After an error page renders, `current.route` is `null`
(`load_root_error_page` stores `route: null` in the navigation state).
The next navigation computes

```js
const route_changed = current.route ? route.id !== current.route.id : false;
```

so the route counts as unchanged no matter where the user goes next. A
root layout server load that tracked `route` is then skipped as fresh,
and its data from before the error page renders on the new page. The new
test's failing assertion on `version-3` shows the layout still claiming
the previous route:

```
Expected: "/b"
Received: "/a"
```

A missing `current.route` now counts as changed. On a first-ever
navigation the flag is irrelevant, the node has no previous data to
reuse anyway, so the only behavior change is the conservative refetch
after error pages.

The interaction was never designed. `route: null` came in #6552 to give
`beforeNavigate` a value meaning "no matched route", and the guard came
two months later in #7450 with route tracking itself, mirroring the
adjacent `url_changed` null-guard. Neither discussed the error-page
case.

The test lives in the no-ssr app. Its root layout gains a server load
returning `route.id`, the navigation's data request is intercepted with
a 500 to produce the error page, and the follow-up navigation must show
the new route id. The app's root `+layout.server.js` was an empty file,
shipped by #11354 so its 404-loop test has a server load node in dev;
giving it a real load keeps that trigger intact.

Found while reviewing #16380, which mirrors this computation for the
error page itself and carries the same one-line fix.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
closes #16468

Warns but keeps working, same as the v2 `files` deprecation. The docs
recommend `resolve.tsconfigPaths` per the issue; its friction with the
generated tsconfig is tracked in #16471.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: Tee Ming <chewteeming01@gmail.com>
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
These were missing for the Netlify and static adapters
Standardises the Netlify adapter docs so that they're similar in
structure to the other adapter docs
Supersedes #16428. It had the right approach, but we were actually
handling `refresh` wrong in the first place. I thought we'd implemented
this behavior but somehow we haven't.

Anyway, this kills two birds with one stone:
- It makes sure we allow `.refresh` (and `.set`) to run during render
- It makes `.refresh` lazy: Calling `.refresh` busts the cache and
guarantees that the cache will be populated by the end of the request.
If you `await` the query or access its data, it will immediately run and
populate the cache; otherwise SvelteKit will do it at the end of the
request, in parallel with any other refreshing queries
closes #14315

This PR adds a utility for checking the spelling of hook files, checks
the spelling for the universal hook file, and checks if an s is missing
from "hooks". Also, only bothers with the check if the file itself has
not been created.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [ ] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
The `.wrangler` directory is generated by Cloudflare Wrangler when
running the Wrangler worker preview and is placed relative to the
wrangler config. This should be ignored no matter where it is, not just
the root of the workspace
Prevents queries from infinitely looping during the drain phase. This
has the side effect of preventing multiple refreshes of the same query
during the drain phase, so... don't do that
…lds.foo.as(...) (#16331)

closes #16321

Made the form ID a suffix so it's easier to read in the browser's
inspector.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
The Vercel server handler files are in a `files` directory. This
directory is where bundled output goes into for all the other adapter
packages except for the Vercel adapter. As a result, it was accidentally
included in the eslint ignore list.

This PR changes that so it's no longer ignored (alternatively, we should
just rename it as `src/`?)
Rich-Harris and others added 18 commits August 14, 2026 12:39
Follow-up to #16795 — this applies the same thinking to `$app/state`. It
allows us to get rid of the awful `BROWSER` hack and colocate logic more
sensibly, with less indirection.

Again, no changeset, since no user-observable changes.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:

- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [ ] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
closes #16785

Basically, paths in the manifest are relative to Vite's configured
`root`, but `write_client_manifest` was resolving them relative to
`process.cwd()`. These are normally the same, but aren't when Vite is
started programmatically from another directory, causing the generated
client manifest to import route files from the wrong place.

Passes the Vite root through to `write_client_manifest` and uses it to
resolve components, universal modules, and param matchers before
generating their imports. Adds a regression test where the project root
differs from `process.cwd()`.
#16794)

On Node, `setResponse` streams every `response.body` through a reader
loop, so a response without a pre-computed `content-length` header is
served with chunked transfer encoding. That is why the runtime can't
move off the deprecated `json`/`text` helpers, whose only load-bearing
job is stamping that header, and why a plain `Response.json` returned
from an endpoint is served chunked today. Every other runtime derives
the header from fixed bodies at serve time.

`setResponse` now races the body's first reads against a `setImmediate`
deadline before writing the head. A fixed body settles value-then-done
on microtasks, so it is sent with a measured `content-length`; a body
that leaves a read pending is a genuine stream and goes through the
existing streaming path unchanged, with its headers delayed by at most
one tick. Nothing is added when the response already carries a
`content-length` or a `transfer-encoding` (proxied responses can carry
the latter, and the pair would be invalid). Same approach as hono's
node-server.

`json`/`text` are untouched. Retiring them internally becomes a
follow-up; its one catch is the `http.response.body.size` span
attribute, which reads the `content-length` header.


#16804 is stacked on this.
as suggested in #16754, modernizes the cloudflare adapter's docs to
mention `wrangler types`. No changeset because docs-only

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:

- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.
Ref #15212.

Something we've wanted to do for a while is get rid of the virtual
modules, in favour of writing stuff to disk. The system becomes a lot
easier to understand when it involves real artifacts instead of the
crazy indirection we have going on at the moment.

I started with the `$app/env/*` stuff because that's likely to be the
most challenging, since it involves some mad science around starting up
a mini Vite dev server to load the `src/env.ts` module so that we can
analyse it so that we can create a generated module that _also_ loads
the `src/env.ts` module... anyway, it works, and so I assume we will be
able to do the same for the other `__sveltekit/*` modules.

(We could probably replace the `resolveId` logic with an alias that just
points to the `generated` folder, same as we have for `$app/*`
currently. That can wait for a follow-up PR though.)

Another thing I'm doing in this PR is creating the plugin in a separate
module, rather than adding to the chaos in `vite/index.js`. It involves
a little bit of duplication, but it makes everything so much more
self-contained, and makes the coupling between different plugins more
explicit (e.g. the `callback`).

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:

- [ ] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Nic Polumeyv <nicolas.polum@outlook.com>
Co-authored-by: Nic Polumeyv <162764842+Nic-Polumeyv@users.noreply.github.com>
closes #<!-- Add the related issue number here. Repeat this line for
each additional issue it closes -->

<!-- Explain the goal of the PR, why it is needed, and what has been
changed to achieve that goal -->

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:

- [ ] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [ ] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [ ] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [ ] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [ ] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
…ercel (#16809)

closes #16806

In a pnpm workspace, `@vercel/nft` can trace the same dependency through
two different symlink chains (e.g. `apps/app/node_modules/X` and
`packages/ui/node_modules/X`) that both realpath to the same file in the
pnpm store. `create_function_bundle` assumed traced file → destination
is 1:1, so the second occurrence hit `fs.symlinkSync` on a `dest` that
already existed and crashed the build with `EEXIST`.

Wraps the symlink in a try/catch that ignores `EEXIST` — both chains
would produce an equivalent link, so skipping the duplicate is safe.
`render_response` types `rendered` with a hand-written `{ head, body,
hashes: { script: string[] } }` and a TODO asking `svelte/server` to
expose `RenderOutput`. The file already imports `render`, so the type is
reachable today, and the hand-written version had drifted from it
(`hashes.script` is `` `sha256-${string}`[] ``).

`Omit` because `SyncRenderOutput` still carries the deprecated `html`,
which neither assignment site sets.

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
)

With #16794, `setResponse` derives `content-length` from fixed bodies,
so runtime responses no longer need the `json` helper to be served
correctly on Node. This switches the runtime's `json` call sites to the
native `Response.json` (deprecated by #15448). `text` call sites stay:
`new Response` with a string body adds a default `text/plain`
content-type where the helper adds none, so replacing those changes
response headers and is a separate decision. Tracing is unaffected,
since page and error documents still go through `text`.

Stacked on #16794; retarget to `version-3` once it merges.

---------

Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
…anonical form (#16339)

closes #14781

During SSR, fetch responses are embedded as `<script
data-sveltekit-fetched data-url=...>` tags, and during hydration the
client rebuilds the url to find them instead of hitting the network. The
two sides build it differently. The server serializes the normalized
href from `new URL(input, event.url)`, while the client keeps the raw
string, because prerendered pages may be served from any origin. That
reasoning holds for same-origin urls, which are serialized
path-relative, but cross-origin urls are absolute on both sides, so a
raw string like `http://localhost:8080` without the trailing slash
misses the cache and the request fires a second time from the browser.

The fix normalizes `requested` to `resolved.href` in the cross-origin
case only. Normalizing in `build_selector` instead, as suggested in the
issue, would break the same-origin case, `new URL('/mock')` throws
without a base. `requested` also became a `const` derived from
`resolved` since the mutation was no longer needed.

The new test fails on main, rendering `count: 2` after the hydration
refetch overwrites the SSR data.

Not fixed here: request bodies are hashed as strings on the server but
dropped from the client hash when they are not strings, so
POST-with-body fetches still miss the cache. Can follow up separately.

Caching under the normalized href also meant a non-GET fetch spelled
without the trailing slash could no longer evict the entry, so the
second commit derives the eviction key the same way.

Also not fixed: on prerendered pages the server classifies same-origin
against `prerender.origin` while the client uses the live origin, so an
absolute url pointing at the deploy origin still misses the cache.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
Follow-up to #16807. Instead of using a `resolveId` hook, we can use an
alias for all the generated modules — every module ID like
`<sveltekit:generated>/foo.js` corresponds to
`.svelte-kit/generated/(build|dev)/foo.js`, making things a little
easier to navigate, and reducing the cost of adding more generated
modules relative to having to faff about with plugin hooks.

The `<sveltekit:generated>` prefix is bikesheddable, but I figured it's
worth being explicit about what this is, and using characters that are
invalid in npm package names.

Creating separate directories for dev and build means we don't need to
be as careful about what goes where, and can freely use relative imports
between generated modules. It means that building while also running a
dev server won't result in clobbering.

We can easily extend this to the other virtual modules.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:

- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [ ] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Nic Polumeyv <nicolas.polum@outlook.com>
Co-authored-by: Nic Polumeyv <162764842+Nic-Polumeyv@users.noreply.github.com>
…ng (#16838)

#16449 made shallow `goto` run navigation hooks by copying two blocks
out of `navigate` into `update_state`: the `onNavigate` callback run
with its `afterNavigate` registration, and the completion tail (abort
check, scroll and focus reset, `fulfil`, `to.scroll`, `afterNavigate`
callbacks). #16685 then had to change both copies. They are now
`run_on_navigate_callbacks` and `finish_navigation`, called from both
places. The second commit builds `navigate`'s not-found fallback once
instead of in two branches that differ only by the message suffix.
…the file's extension (#16837)

`create_manifest_data` warns `Did you mean +${file.name}?` for any file
whose name matches either the component or the module grammar, ignoring
the extension. For `routes/a/error.ts` it suggests `+error.ts`, and
renaming to that throws `Files prefixed with + are reserved`. The two
grammars were also written out three times in the file; they're now two
module-level patterns and the typo check picks the one matching the
extension.

Co-authored-by: Nic Polumeyv <nicolas.polum@gmail.com>
…ge to the correct trailing slash (#16836)

The trailing-slash redirect for prerendered pages in
`exports/vite/preview/index.js` writes an absolute `location` from the
pathname the middleware sees, but that middleware runs inside
`scoped(base, ...)`, which has already stripped `paths.base`. With a
base path the browser lands on `/nested/` instead of `/base/nested/`.
Production (#9351) and adapter-node (#16431) send a relative location
for this reason and use 308; preview now does the same via
`relative_pathname`.

---------

Co-authored-by: Nic Polumeyv <nicolas.polum@gmail.com>
`utils/path.js` lost its only importer in #16374, `decode_params` in
#16189, `strip_virtual_prefix` in #16450.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Tee Ming <chewteeming01@gmail.com>
This PR gets rid of all the virtual modules, in favour of using real
modules in `.svelte-kit/generated`.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:

- [ ] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [ ] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Tee Ming <chewteeming01@gmail.com>
@teemingc

teemingc commented Aug 18, 2026

Copy link
Copy Markdown
Member Author

The release action is broken because of the number of commits on the branch changesets/changesets#2247

EDIT: it somehow fixed itself?

Rich-Harris and others added 11 commits August 19, 2026 01:01
…on-existent routes (#16376)

closes #12910

When the client renders an error page for a URL that matches no route,
the root layout's server data goes missing. The universal `+layout.ts`
load receives `data: null` even though the server runs that exact load
function to render the HTML 404. Reported with `ssr = false`, but any
client-side navigation to a non-existent route hits it.

```
GET /this-route-does-not-exist/__data.json?x-sveltekit-invalidated=1

before  404 text/html          (the rendered error page)
after   200 application/json   {"type":"data","nodes":[{"type":"data","data":[{"rootlayout":1},"rootlayout"],"uses":{}}]}
```

`load_root_error_page` fetches `__data.json` when the root layout has a
server load, sending `x-sveltekit-invalidated=1` for the single root
node. The server matches no route and falls through to the `state.depth
=== 0` branch in `respond.js`, which renders the HTML error page. That
branch predates data requests, so they were never special-cased there,
and the render runs the root layout server load only to discard the
result as HTML. Client-side `load_data` then throws `HttpError(404)`,
which since #16135 is deliberately swallowed to avoid a reload loop,
leaving `server_data_node` null.

teemingc diagnosed this on the issue and named two acceptable outcomes,
"We need to be able to return layout data for an error page although a
route doesn't exist or just return the fallback error page." This PR
implements the first, server side only. The client already consumes the
response, and the fallback option would discard data the server computes
anyway while rendering the HTML 404. No client changes.

The new branch only fires for `is_data_request &&
invalidated_data_nodes?.length === 1`. The invalidation parameter marks
kit's own `load_data` fetches, so a browser navigating directly to a
`.../__data.json` URL keeps getting the HTML error page that #15884
deliberately improved (its options-2 test still passes). Length 1 is
exactly the shape `load_root_error_page` sends, so an old deployed
client requesting multi-node data for a route that no longer exists on
the new server keeps today's 404 instead of receiving a truncated nodes
array. Prerendering is excluded so a missing path still reports 404 for
dead-link detection.

The response reuses `render_data` with a synthetic root page (`layouts:
[], leaf: 0`), so load execution, serialization, streaming, redirect and
error nodes all behave as they do for matched routes. Its `route` JSDoc
is narrowed to the two fields it reads instead of casting the synthetic
object to a full `SSRRoute`. Static hosts are unaffected, there is no
server to return the data, and #16135 already keeps the fallback page
from looping there.

The new test in the basics `Errors` describe asserts both halves, JSON
with the parameter and HTML 404 without it. Fails on `version-3` without
the `respond.js` change.

Sibling PR #16380 touches the client half of this flow (reusing fresh
root layout data instead of refetching). The two compose, whichever
lands second rebases trivially.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: Nic Polumeyv <nicolas.polum@gmail.com>
…non-ActionResult error response (#16308)

closes #15737

Submitting a `use:enhance` form that trips the CSRF origin check does
nothing visible. The 403 response is right there in the network tab:

```json
{ "message": "Cross-site POST form submissions are forbidden" }
```

but it has no `type`, so it isn't an ActionResult and every branch in
the submit handler and `applyAction` skips it. Non-JSON responses
already become `{ type: 'error' }` through the catch around
`deserialize`, so JSON that isn't an ActionResult was the one shape that
failed silently.

Error responses without a recognized `type` now throw into that same
catch and render the nearest `+error.svelte`. A body shaped like an
`App.Error` becomes `page.error` as-is, the way an `error(403, { message
})` body does. Anything else goes through `handleError`, which #16162
routed this catch through, so the hook keeps seeing these failures and
`page.error` keeps its declared shape. 2xx responses are untouched.

PatrickG suggested rendering the error page in the issue. teemingc
flagged the same gap in #10464 with a server-side shape fix in mind;
doing it on the client also covers proxy and middleware responses that
kit's server never shaped. #10855 reports the same class of unhelpful
failure for non-action endpoints; the non-2xx half of it is covered
here.

Responses that do parse as an ActionResult pass through regardless of
status, which keeps the pattern that prompted the #13197 revert (#13397)
working. The docs line that revert added says posting to a `+server.js`
endpoint results in an error; with this change that error surfaces
instead of failing silently.

The test mimics the CSRF response with an endpoint, since the real check
can't fire same-origin in Playwright. It fails on `version-3` and passes
with this change, in dev and build. The hook suffix in two of the
assertions is `handleError` running.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: Nic Polumeyv <nicolas.polum@gmail.com>
Co-authored-by: Rich Harris <rich.harris@vercel.com>
…16443)

Implements the `name` property from
#16424 (comment).

`name` is looked up from the Vite client manifest where the fonts arrays
are built, so the filter receives the exact source file name. Deriving
it from the emitted path was wrong two ways, the bundler sanitizes
characters (`inter+bold.woff2` is emitted as `inter_bold.<hash>.woff2`)
and content-identical assets are emitted once under a single name. The
union includes `name` for `font` only, kit never calls `preload` with
type `asset`.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits
- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
`read_stream` accumulates decoded text in one string, re-runs `indexOf`
over the whole buffer after every transport chunk and re-slices the
buffer for every emitted record. When one frame spans many chunks, every
prefix is rescanned and total work grows quadratically with frame size.
This parser sits behind streamed page data and remote functions (NDJSON)
and `query.live` (SSE), so the cost lands on the client for large
payloads.

With this change only newly decoded text is searched. Already searched
text accumulates in an array and is joined once per completed frame. The
last `delimiter.length - 1` characters stay in the unsearched tail so a
delimiter split across chunk boundaries still matches.

One 2 MiB frame, Node 22 x64, median of repeated runs:

| transport chunks | before | after | speedup |
| ---: | ---: | ---: | ---: |
| 2048 × 1 KiB | 1720.7 ms | 4.0 ms | 429× |
| 512 × 4 KiB | 431.0 ms | 3.2 ms | 135× |
| 128 × 16 KiB | 111.5 ms | 3.1 ms | 36× |
| 32 × 64 KiB | 31.3 ms | 3.1 ms | 10× |

Many small records, the common path, get slightly faster (2 MiB of 64
byte records in 16 KiB chunks, ~21 ms to ~15 ms) because the old code
re-sliced the buffer once per record.

Output is unchanged. The rewrite matched the previous implementation
across 4000 randomized cases covering both delimiters, delimiters split
between chunks, multibyte UTF-8 split between chunks and trailing
unterminated records. The new unit tests also pass against the previous
implementation.

`read_stream` was extracted in #15957 and last changed in #16423. No
open PR modifies `stream.js`, `ndjson.js` or `sse.js`.

---

### Before submitting the PR, please make sure you do the following

- [ ] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.
…ch parameter changes (#16495)

Since #11258, `diff_search_params` compares each key's values as a set,
so navigating from `?x=a&x=a` to `?x=a` is treated as unchanged and load
functions tracking `x` don't rerun. Comparing the sorted value lists
instead catches count changes, still treats reordering as unchanged, and
is O(V log V) rather than O(V²).

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:

- [ ] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests

- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets

- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. All changesets should be `patch` until
SvelteKit 2.0 (major releases only that fix regressions)

### Edits

- [ ] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.
`core/env.js` had one generator per `<sveltekit:generated>/env/*`
module, each iterating the same variables and calling `validate()` on
the same static values, so a user's schema ran three to four times per
build (and per hot update in dev), and a validator that isn't a pure
function of its input baked different values into `config.js`,
`public/server.js` and `public/client.js`.

`create_env_modules` replaces them with a single pass over the variables
that returns every module keyed by path, so the plugin only writes
files. Dynamic variables are untouched; they were already validated once
by `set_env`.

One visible change: invalid variables that previously surfaced one
module at a time are now reported in a single error.
`client.js` walks `query_map` and `live_query_map` eight times across
`_invalidate` and `_goto`, each as a hand-written `for (const [id,
entries] of map) for (const [payload, entry] of entries)` pair, and five
of those recompute `create_remote_key(id, payload)` inline to get the
key the consumer actually wants.

This adds a `cache_entries(map)` generator yielding `[key, entry]` and
collapses each site to a single loop. No behaviour change; the walk
order and the set of resources touched are identical.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.
`handle_action_json_request` in `runtime/server/page/actions.js` was a
copy of `handle_action_request` that differed only in how each branch
was encoded, and the 405 result was written out a third time in
`handle_remote_form_post_internal`
(`runtime/server/remote-functions.js`). #16684 had to add `location` to
every copy. `handle_action_request` now runs once and
`action_result_json` encodes the result for the JSON transport;
`method_not_allowed_result` and `action_error_result` are shared with
the remote form POST handler.

The `fail()` misuse check is no longer in the shared catch, since
`fail()` is form-action only. Remote `form` handlers get a dev-time
error for a thrown or returned `fail()` in `app/server/remote/form.js`,
covering both the enhanced and no-JS transports.

`ServerActionResult` (`types/internal.d.ts`) types the pre-`handleError`
result, so we're no longer lying about the types.

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
…6720)

closes #16696

`validate()` checks `element` before `await tick()`, but the attachment
cleanup sets `element = null` when the `<form>` unmounts. If the form is
removed while `validate()` is waiting for that tick — e.g. an `{#if}`
flips right after a fast submission — the resumed call throws:

```
TypeError: Cannot read properties of null (reading 'querySelector')
```

The fix re-checks `element` after the tick and bails out if the form is
gone, which matches what the pre-tick check already intends.

### Tests

Added a case to the `async` test app's existing `/remote/form/validate`
route: a form inside an `{#if}` block, and a button that starts
`validate()` and unmounts the form in the same handler, catching
whatever the promise rejects with. The new test fails on `version-3`
(`TypeError: Cannot read properties of null (reading 'querySelector')`)
and passes with this change.

Rebased onto `version-3` at a115a7b and re-verified locally on Node
24.18.0:

- `pnpm lint`: 0 errors (one pre-existing warning in
`src/runtime/server/page/index.js`, untouched here).
- `pnpm test:unit`: 895 passed, 11 failed. The 11 failures are in
`kit-prerendering-paths-base` and `kit-prerendering-options` and
reproduce identically on unpatched `version-3`, so they are not from
this change.
- `async` test app, `pnpm test:dev`: 193 passed, 103 skipped, 0 failed.
The new test also passes in `chromium-build` and `chromium-build-no-js`.
- `pnpm check` fails on unpatched `version-3` as well, with 24 `TS2300:
Duplicate identifier` errors from `src/types/ambient.d.ts`. This branch
changes no types, so I could not get a clean baseline for that step.

---

### Please don't delete this checklist! Before submitting the PR, please
make sure you do the following:
- [x] It's really useful if your PR references an issue where it is
discussed ahead of time. In many cases, features are absent for a
reason. For large changes, please create an RFC:
https://github.com/sveltejs/rfcs
- [x] This message body should clearly illustrate what problems it
solves.
- [x] Ideally, include a test that fails without this PR but passes with
it.

### Tests
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint` and `pnpm check`

### Changesets
- [x] If your PR makes a change that should be noted in one or more
packages' changelogs, generate a changeset by running `pnpm changeset`
and following the prompts. Changesets that add features should be
`minor` and those that fix bugs should be `patch`. Please prefix
changeset messages with `feat:`, `fix:`, or `chore:`.

### Edits

- [x] Please ensure that 'Allow edits from maintainers' is checked. PRs
without this option may be closed.

---------

Co-authored-by: Elliott Johnson <hello@ell.iott.dev>
Co-authored-by: Rich Harris <rich.harris@vercel.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.