Each `<svelte:boundary>` with:
```svelte
{#snippet failed(error)}
...
{/snippet}
```
generated a function named failed. Sibling boundaries placed both
functions in the same SSR scope:
```js
{
function failed() {}
function failed() {} // Identifier `failed` has already been declared
}
```
Resulting in a `[PARSE_ERROR] Identifier `failed` has already been
declared` error during build time.
A let declaration such as `{const x = 0}` can create a nested lexical
block, exposing the collision.
The fix gives each boundary its own scope:
```js
{
function failed() {}
$$renderer.boundary({ failed }, ...);
}
{
function failed() {}
$$renderer.boundary({ failed }, ...);
}
``
`render` returns `RenderOutput` and takes `csp: Csp`, but both are
declared in `src/internal/server/types.d.ts` and never exported. The
generated `svelte/server` block has them without `export`, so nothing
outside the repo can import them and the docs page names `RenderOutput`
as the return type with nothing on the page defining it.
Moves them into `src/server/public.d.ts` the way `svelte/motion` went in
#17967, rather than re-exporting internals.
Fixes#18440
`hmr()` in `packages/svelte/src/internal/client/dev/hmr.js` wrapped a
component in a `block` effect containing a `branch` effect. It forwarded
the inner effect's `nodes` object to the outer block:
This shared the same reference, meaning `outer_block.nodes ===
inner_branch.nodes`. When `pause_children` collected transitions for
unmounting, Each collected transition had `out(check)` called multiple times,
starting multiple animations and firing `outroend` multiple times.
Fix by only copying `start`/`end` (the DOM range info the outer block needs)
without sharing the transitions array:
`trace_references` recreated a fresh seen set for every CallExpression,
so `touch` re-walked the same transitive assignment graph once per call.
For N calls reaching an N-deep binding chain, this was $O(N^2)$.
Share one seen set per trace_references invocation. Use separate sets
for the write-directed CallExpression touches and the read-directed
ReturnStatement touches. The shared set ensures each assignment-value
expression is walked at most once, making the traversal linear. `touch`
only ever adds to a fixed target set, so skipping an already-seen
expression never drops a binding: compiler output is byte-identical.
Complements #18548.
---------
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
`to_style()` strips CSS comments from an inline `style` value with
`/\s*\/\*.*?\*\/\s*/g`. The leading `\s*` makes the match retry from
every position, so a long run of whitespace backtracks in O(n^2). When a
dynamic `style={value}` sits on an element that also has a `style:`
directive, that regex runs on `value`, so a large whitespace string can
stall rendering (server) or the main thread (client).
### Fix
Drop the surrounding `\s*` and match only the comment: `/\/\*.*?\*\//g` to prevent quadratic regex.
The surrounding whitespace was already removed by the `.trim()`
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
Fixes#18568
`last_propagated_event` was added in #16527 to stop Firefox from garbage collecting the event wrapper mid-propagation. The problem with this is that the even is now retained until the next event, which could be a while. This removes it after a macrotask.
Co-authored-by: rmurphy <rmurphy@fortressinfosec.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Switch `@svitejs/changesets-changelog-github-compact` to
`@changesets/changelog-github` (its new `template` option reproduces the
same compact output).
Fixes#7916. Context lookup starts at the current component, not the
closest parent. `setContext` followed by `getContext` with the same key
in the same component returns the value.
---------
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
The server copy of `createContext` shipped without the `missing_context`
throw and #17580 had to hand-mirror the client body back in, so this
duplication has already cost a bug. This moves the realm-independent
parts, the `createContext` tuple, `get_parent_context`, and
`get_or_init_context_map`, into `internal/shared/context.js`, and each
realm keeps its public context functions as thin wrappers over its own
state.
Fixes#18609
A `<an+b> of <selector>` CSS statement does not need whitespace after `of` if it's followed by a CSS-known syntax (like a `.` which marks a class identifier). Adjust the regex accordingly.
Fixes#18612.
A concise arrow body does not contain a `ReturnStatement` which we traverse in full calculate_blockers (else we bail on functions), so short-cut to `touch` there.
---------
Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
Fixes#18288
Check the surrounding branch effect's start node to retrieve the correct root node instead of just the anchor, since the latter could come from each.js/branch.js and be a text node that is never going to get connected
---------
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
Fixes#18404
`<svelte:head>` combined with two or more components that each use `bind:` on a child component's prop corrupts a renderer's `.type` during SSR, misplacing the head hydration marker in `<body>` instead of `<head>`.
Reason: `copy()` (`packages/svelte/src/internal/server/renderer.js`) rebuilds via `new Renderer(this.global, this.#parent)`. That constructor defaults `.type` from the *parent's* current type, not from `this.type`. To fix it we therefore reassign it (like already do for the boundary elsewhere)
Fixes#18677.
- preserve namespace prefixes on CSS `TypeSelector` AST nodes
- accept wildcard local names in `svg|*` and `*|*`
- retain namespaces when printing modern ASTs
- keep namespaced universal selectors intact while adding scoped CSS
selectors
- add compile and print regressions covering all four namespace forms
---------
Co-authored-by: svelte-triage-bot <team@svelte.com>
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
Fixes#18664
`print()` was writing selector names back out verbatim. The parser
decodes CSS escape sequences when it reads them — `\31` becomes `1`,
`\a` becomes a newline — so the printer produced selectors that either
failed to re-parse (`#123`) or silently meant something different
(`#line\nbreak` turns into a descendant combinator).
A small re-escaper (`escape_identifier`) is now used when printing type,
class, id, pseudo, attribute and at-rule names.
Also fixes a backslash parser bug in the process.
---------
Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
Hi! This PR fixes#18666
### 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] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`.
- [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.
- [x] If this PR changes code within `packages/svelte/src`, add a
changeset (`npx changeset`).
### Tests and linting
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint`
Fixes#18592.
Logical assignments to private `$state` fields were compiled as
unconditional setter calls. This preserves JavaScript short-circuiting
by evaluating the setter only when `||=`, `&&=`, or `??=` should assign.
The regression sample covers the no-assignment branch for all three
operators, alongside the existing assignment-path coverage.
### 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] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`.
- [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.
- [x] If this PR changes code within `packages/svelte/src`, add a
changeset (`npx changeset`).
### Tests and linting
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint`
Fixes#18304
The parent of a declaration could be the Program, on which HTML comments are added, which subsequently crashes the funciton. Ignore such comments.
---------
Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
Fixes#18608.
When `set_attributes` normalized removed spread attributes, it also
copied its internal `$$` listener bookkeeping keys into `next` with a
`null` value. This cleared the stored callback before event cleanup, so
removing a capture handler passed `null` to `removeEventListener` and
left the listener attached.
Skip internal `$$` keys during missing-attribute normalization. The
updated runtime-runes sample verifies replacing and then removing a
spread capture handler in both client and hydration modes.
---------
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
Fixes#18619
Make sure to not override old values with newer values that are part of the same flush
---------
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
Fixes https://github.com/sveltejs/svelte/issues/18607.
For server output, `build_getter` reused a derived binding's declaration
identifier as the generated call callee. Esrap therefore associated
leading declaration comments with an earlier reference, potentially
emitting them immediately after `return` and triggering automatic
semicolon insertion. The getter returned `undefined` instead of the
derived value.
Fix it by avoiding the double-transform.
---------
Co-authored-by: svelte-triage-bot[bot] <316883489+svelte-triage-bot[bot]@users.noreply.github.com>
Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
- preserve whitespace around elements if it leads to a line break
- preserve whitespace for whitespace-sensitive elements (pre, textarea,
title)
Co-authored-by: Rich Harris <rich.harris@vercel.com>
Adds a new `comments` array to the stylesheet node which CSS comments
are added to. Is subsequently used in `print` to see them in the output.
Alternative to #18475
Fixes#18610
### Problem
In async mode, a controlled keyed `{#each}` throws `TypeError: Cannot
read properties of undefined (reading 'e')` when its collection becomes
empty while an earlier batch is still pending on the same block.
The fast path in `pause_effects` cleared `state.items` and then called
`destroy_effects`, which walks pending batch keys and reads
`state.items.get(key).e`. Those EachItems are still needed for the
pending batch (preserved offscreen), so clearing the map makes the
dereference throw and aborts the commit mid-flight.
### Fix
Only take the controlled-each fast path when `state.pending.size === 0`,
so pending batches keep their items until they commit or discard.
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 main, this PR will
be updated.
# Releases
## svelte@5.56.8
### Patch Changes
- fix: call `onerror` and provide a working `reset` when hydrating a
failed boundary
([#18556](https://github.com/sveltejs/svelte/pull/18556))
- fix: preserve select selection when spread attributes omit value
([#18561](https://github.com/sveltejs/svelte/pull/18561))
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Fixes#18555
A boundary that failed during SSR hydrates via
`#hydrate_failed_content`, which never calls `onerror` and passes the
`failed` snippet a no-op `reset`. Both came in with #17672, whose docs
say `onerror` "will be called upon hydration with the deserialized error
object". Once hydrated as failed, the boundary can never leave that
state. Downstream this is what keeps SvelteKit's `+error.svelte` mounted
after navigating away from a server-rendered error page
(sveltejs/kit#16345).
This extracts the reset/onerror machinery from `#handle_error` into
`#create_reset` and uses it in the hydration path too. `onerror` is
invoked in a microtask because it may mutate state, which is disallowed
while hydrating. `#handle_error` already invokes it asynchronously, so
the timing matches the error path.
The tests flip a `recovered` flag before calling `reset`, since the
child would otherwise throw again. That is the intended retry pattern,
and the same one kit uses when it resets route boundaries on navigation.
Verified against kit end to end, hydrating a server-rendered error page
and navigating away now tears it down with no kit changes needed.
Fixes#18557
A `<select>` with spread attributes initializes the option mutation
observer even when those attributes never provide a `value`. In that
case the element has no internal `__value`, but the observer previously
treated the missing property as an explicit `undefined` value and
deselected every option after an option was added or removed.
Only reapply the programmatic selection when `__value` is actually
present. This preserves the browser's current selection for spreads
without a value while keeping the existing behavior for bindings,
including an explicitly stored `undefined` value.
A runtime-legacy regression fixture covers both adding and removing an
option in client and hydration modes.
### Before submitting
- [x] References the existing issue
- [x] Uses a `fix:` title
- [x] Includes a regression test
- [x] Includes a patch changeset for `svelte`
### Test plan
- [x] `FILTER=select-spread-preserve-selection pnpm test runtime-legacy
--maxWorkers=1` (2 tests passed: client and hydrate)
- [x] `git diff --check`
- [ ] Full `pnpm test` was not run because the shared host was under
resource pressure and broad test processes were explicitly avoided
- [ ] `pnpm lint` and `pnpm check` were not run for the same reason
- [ ] Targeted repository Prettier check was attempted, but could not
start because `prettier-plugin-svelte` required the ungenerated
`packages/svelte/compiler/index.js`; no broad build or dependency
reinstall was run
### AI disclosure
AI-assisted: the implementation, regression test, and pull request text
were prepared with OpenAI Codex and reviewed by the contributor.
Co-authored-by: Paolo Ricciuti <ricciutipaolo@gmail.com>
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 main, this PR will
be updated.
# Releases
## svelte@5.56.7
### Patch Changes
- chore: provide `indent` option for `print`
([#18474](https://github.com/sveltejs/svelte/pull/18474))
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Relevant for https://github.com/sveltejs/cli/pull/1138.
This is basically just an option from `esrap` that we pass through. That
will allow tools like `sv migrate` to provide a guessed indent based on
the other file contents and therefore allow us to produce way smaller
diffs. Since we are just passing an option, there is no need for a test
here.
Technically a `feat:` but i dont think this is relevant enough.
### 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] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`.
- [x] This message body should clearly illustrate what problems it
solves.
- [ ] Ideally, include a test that fails without this PR but passes with
it.
- [x] If this PR changes code within `packages/svelte/src`, add a
changeset (`npx changeset`).
### Tests and linting
- [x] Run the tests with `pnpm test` and lint the project with `pnpm
lint`
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 main, this PR will
be updated.
# Releases
## svelte@5.56.6
### Patch Changes
- perf: skip unnecessary blocker analysis when compiling components
without top-level await
([#18548](https://github.com/sveltejs/svelte/pull/18548))
- fix: rerun derived that had an abort controller on reconnection
([#18551](https://github.com/sveltejs/svelte/pull/18551))
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Skip function reference tracing in `calculate_blockers` when a component
has no top-level `await`.
Blockers only represent dependencies on top-level async statements.
Without a top-level `await`, no binding can have a blocker, so tracing
every top-level function cannot affect the generated output. In large
components with many functions and transitive assignments, that
unnecessary work can become quadratic.
Follow-up to #18400 - we need to mark a derived with an abort signal
that is frozen as dirty so it is guaranteed to rerun when it
reconnects/is re-requested. Else you could return a stale value, or
worse, you returned a promise from the derived which you aborted, and
it's now in the rejected state until you update one of its dependencies.
Fixes https://github.com/sveltejs/svelte/issues/18301
---------
Co-authored-by: Fedor Nezhivoi <f.nezhivoi@corp.vk.com>
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
fixes#18438
Currently the `mark` method inside `#merge` for `earlier_batch` will
schedule effect for undirty derived. Add the condition for derived to
prevent unnecessary effect be scheduled.
```
if ((flags & DERIVED) !== 0) {
mark(/** @type {Derived} */ (reaction));
}
```
## Summary
Fixes#18491 — the compiler discards an upstream plugin's sourcemap when
it's generated without a `source` option (e.g. `new
MagicString(code).generateMap()`), producing wrong devtools/stack-trace
positions.
### Root cause
`compile()` already supports composing an incoming sourcemap into its
output via `options.sourcemap` (`merge_with_preprocessor_map` →
`apply_preprocessor_sourcemap` → `combine_sourcemaps` in
`packages/svelte/src/compiler/utils/mapped_code.js`). This is the same
mechanism `preprocess()` uses internally, and it's the documented
contract for tools that transform a `.svelte` file before compiling it
(see `CompileOptions.sourcemap`'s doc comment).
`combine_sourcemaps` composes maps by matching `sourcefile === filename`
(the basename of the file being compiled). A sourcemap produced by `new
MagicString(code).generateMap()` **without** a `source` option — which
is exactly what the reporter's Vite plugin does — has `sources: ['']`.
That empty string never equals `filename`, so `remapping()` treats the
node as a leaf (the "original" file) instead of a branch to keep
chaining through, and the whole incoming map is silently dropped. The
result: every position that flows through that segment resolves to `{
source: null, line: null, column: null }`, which is what produces the
wrong/missing devtools mapping described in the issue.
Vite itself already has to handle this exact ambiguity: in
`pluginContainer.ts`'s `_getCombinedSourcemap`, an empty `sources[0]`
from a MagicString-based transform is patched to refer to the file being
transformed before Vite uses it internally. This PR applies the same
normalization on svelte's side, so the contract holds regardless of
whether the caller happens to pass a `source` option to `generateMap()`.
### Fix
In `apply_preprocessor_sourcemap`, normalize an incoming map's `sources:
['']` (or `[null]`/`[undefined]`) to `[filename]` before calling
`combine_sourcemaps`, so the chain-matching step can actually find it.