This commit fixes the issue reported at packages/svelte/src/reactivity/set.js:92
**Bug Explanation:**
After the refactoring to make SvelteSet async-safe, the data storage changed:
- **Before:** Data was stored in the underlying Set via `super.add()` in the constructor
- **After:** Data is stored in a reactive `#items` source containing a Set, while `super()` is called without arguments (empty Set)
The `#init()` method creates implementations for `read_methods` and `set_like_methods` by delegating to `Set.prototype` methods. However, the code used `set_proto[method].apply(this, v)` where `this` is the SvelteSet instance. Since SvelteSet extends Set but never adds items to itself (all data is in `#items`), calling these Set methods on `this` operates on an empty Set.
This caused severe bugs:
- `forEach()` would iterate over nothing instead of actual items
- `isSubsetOf()` would always return `true` (empty set is subset of everything)
- `isSupersetOf()` would always return `false` (empty set can't be superset of non-empty)
- `union()` would only return the other set (union with empty set)
- `intersection()` would return empty (intersection with empty set)
- `difference()` would return empty
- `symmetricDifference()` would just return the other set's items
**The Fix:**
Changed `set_proto[method].apply(this, v)` to `set_proto[method].apply(get(this.#items), v)` in both loops.
This ensures the Set methods operate on the actual data stored in `#items` (the reactive Set that contains all the items) rather than the empty underlying Set that the SvelteSet class extends.
The fix maintains reactivity since `get(this.#items)` is still called, establishing the reactive dependency as intended.
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Rich-Harris <hello@rich-harris.dev>
This is part of me trying to figure out #17162. It feels less confusing
to rebase other branches after the current batch has been processed,
rather than sort of doing it in the middle (which is an artifact of
historical constraints that no longer apply).
No test because it doesn't change any user-observable behaviour (but I
added a changeset just in case)
### 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.53.10
### Patch Changes
- fix: re-process batch if new root effects were scheduled
([#17895](https://github.com/sveltejs/svelte/pull/17895))
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
In some cases a new branch might create effects which via
reading/writing reschedule an effect, causing `this.#roots` to become
populated again. In this case we need to re-process the batch. Most of
the time this will just result in a cleanup of the dirtied branches
since other work is already handled via running the effects etc. - it's
still crucial, else the reactive graph becomes frozen since no new root
effects are scheduled.
Fixes#17891
---------
Co-authored-by: Rich Harris <rich.harris@vercel.com>
### Summary
Fix spelling in the v5 migration guide ("useable" -> "usable").
### 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] 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.
- [ ] If this PR changes code within `packages/svelte/src`, add a
changeset (`npx changeset`). (Not applicable; docs-only change.)
### Tests and linting
- [ ] Run the tests with `pnpm test` and lint the project with `pnpm
lint`. (Not run; docs-only change.)
Co-authored-by: rohan436 <rohan.santhoshkumar@googlemail.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.53.9
### Patch Changes
- fix: better `bind:this` cleanup timing
([#17885](https://github.com/sveltejs/svelte/pull/17885))
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
This removes the `queue_micro_task`-workaround we employed in
`bind:this` in favor of a search for the nearest component effect /
effect that is still getting destroyed, whichever comes first.
We used `queue_micro_task` mainly due to timing issues with components
wanting to access the bound property on teardown still, and when nulling
it out on cleanup of the bind-this-effect itself, that was too early.
The microtask is too late though in some cases, when accessing
properties of objects that are no longer there. The targeted
upwards-walk solves this while keeping the binding around as long as
needed.
For that I had to add a new `DESTROYING` flag. We _could_ have done it
without one and by deleting code in `props.js` where we don't do
`get(d)` when the prop derived is destroyed, but I wanted to keep that
because you could still run into an access error if you e.g. access the
property in a timeout.
Alternative to #17862
This adds a `skill: true` to the frontmatter of the bestpractices
skill/doc. This way when we sync we can concern ourselves to only the
documents that need to be skills (we will write one for sveltekit too)
without targeting specific files in the `ai-tools` repo
In #17837 we added logic to not schedule another batch during
resumption. The logic in there turns out to be flawed - it's dangerous
to keep accessing inert block effects, because if they're nested they
could access properties that no longer exist (because the outer if makes
the inner if obsolete).
So this PR basically reverts #17837 and instead schedules another batch
again under the assumption that this will only happen during the commit
phase, and all that's gonna happen is that it will schedule another
batch, which is safe.
Fixes#17866Fixes#17878
This reverts commit 2f12b60701.
Co-authored-by: Rich Harris <rich.harris@vercel.com>
The combination of #17873 and #17805 resulted in a bad merge of the
latter because it wasn't up to date with main. This fixes it. No
changeset because not released yet.
---------
Co-authored-by: Rich Harris <rich.harris@vercel.com>
This simplifies the scheduling logic and will likely improve performance
in some cases. Previously, there was a global `queued_root_effects`
array, and we would cycle through the batch flushing logic as long as it
was non-empty. This was a very loosey-goosey approach that was
appropriate in the pre-async world, but has gradually become a source of
confusion.
Now, effects are scheduled within the context of a specific batch. The
lifecycle is more rigorous and debuggable. This opens the door to
explorations of alternative approaches, such as only scheduling effects
when we call `batch.flush()`, which _may_ be better than the eager
status quo.
The layout of the `Batch` class is extremely chaotic —
public/private/static fields/methods are all jumbled up together — and I
would like to get a grip of it. In the interests of minimising diff
noise that ought to be a follow-up rather than part of this PR.
### 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`
---------
Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
When an async value is updated inside the boundary while the pending
snippet is shown, we previously didn't notice that update and instead
showed an outdated value once it resolved. This fixes that by rejecting
all deferreds inside an async_derived while the pending snippet is
shown.
---------
Co-authored-by: Rich Harris <rich.harris@vercel.com>
Fixes `{@html}` content duplication when used inside a contenteditable
element.
When `{@html content}` is inside a contenteditable element and the user
types, the browser inserts DOM nodes directly into the {@html} managed
region. On re-render (e.g. triggered by a blur handler setting `content
= e.currentTarget.innerText`, the `{@html} `block only removed nodes it
previously created via` effect.nodes`, leaving browser-inserted nodes in
place. This caused content to appear twice — once as leftover text nodes
and once as the new `{@html}` output.
The fix tracks the boundary node (`previousSibling `of the anchor at
init) and removes all nodes between the boundary and the anchor on
re-render, ensuring externally-added nodes are also cleaned up.
Closes: #16993
---------
Co-authored-by: 7nik <kfiiranet@gmail.com>
Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
Extracted from #17805. Similar to #17864, I'm not aware of any bugs
resulting from this, but the fact that we're setting `current_batch`
before calling `internal_set` and then not _unsetting_ `current_batch`
feels like something that could potentially bite us.
If an assignment happens in a `$:` statement, any affected effects are
rescheduled while the traversal is ongoing. But this is wasteful — it
results in the `flush_effects` loop running another time, even though
the affected effects are guaranteed to be visited _later_ in the
traversal (unless the thing being updated is a store).
This PR fixes it: inside a `legacy_pre_effect`, we temporarily pretend
that the branch _containing_ the component with the `$:` statement is
the `active_effect`, such that Svelte understands that any marked
effects are about to be visited and thus don't need to be scheduled. We
deal with the store case by temporarily pretending that there _is_ no
`active_effect`.
I will be delighted when we can rip all this legacy stuff out of the
codebase.
### 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`
Extracted from #17805. Currently we restore context in`flatten`
unnecessarily in the case where we have async expressions but no
blockers (the context is already correct), and we don't unset context
after blockers resolve in the case where we have them. The first bit is
suboptimal, but the second bit feels bug-shaped, even though I'm not
currently aware of any actual bugs that have resulted from this.
### 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.
- [ ] 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 is #17850 with changes (for whatever reason I wasn't able to push
direct to the fork) — same test but simplified, and a simpler fix that
doesn't undo the recent (necessary!) changes to the scheduling logic
---------
Co-authored-by: Mattias Granlund <mtsgrd@gmail.com>
Fixes a runtime edge case where keyed #each reconciliation can hit a
missing item during deferred async updates, causing an internal crash
and masking the original boundary error.
Fixes#17841
### 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
- [] Run the tests with `pnpm test` and lint the project with `pnpm
lint`
---------
Co-authored-by: Rich Harris <rich.harris@vercel.com>
## Summary
`Scope.generate()` and `ScopeRoot.unique()` search for available names
by iterating from suffix `_1` upward. When the same preferred name is
generated many times (e.g. `text` is generated 482 times in a large
component), the Nth call re-scans all N-1 already-taken names — O(n²)
total work.
This adds a `#name_counters` Map to `ScopeRoot` that tracks the next
suffix to try per name, so each call resumes from where the last one
left off. Generated names are identical to before.
## Benchmark (interleaved, best-of-3 rounds)
| Component | Min | Median |
|---|---|---|
| Realistic (~80 lines) | ~1% | ~7% |
| Medium (316 lines) | ~1% | ~5% |
| Large (642 lines) | ~7% | ~2% |
| XLarge (1302 lines) | **~11%** | **~10%** |
## Test plan
- [x] All snapshot tests pass (name generation unchanged)
- [x] All validator, compiler-error, runtime-runes, runtime-legacy tests
pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
If a dirty effect is resumed — for example `condition` becomes `false`
then `count` changes then `condition` becomes `true` again...
```svelte
{#if condition}
<div transition:fade>
{count}
</div>
{/if}
```
...then the effect is rescheduled. This happens when branches are
committed (after the effect tree is traversed, before effects are
flushed).
That's undesirable, because it causes another turn of the
`flush_effects` loop. It's better if we can handle everything in a
single pass, which is what happens in this PR. The trade-off is that we
have to traverse the entire effect tree, instead of skipping inert
subtrees, which is a trade-off that I think makes sense.
The real agenda here is that I'm trying to eliminate all
`schedule_effect` calls that happen at inconvenient times, because I
have a hunch that if we do that we can return to #17805, which I'm
increasingly convinced will be important. (You might have to trust me on
this; a full explanation would look a bit charlie-day-meme.jpg. Call it
a hunch.)
### 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`
---------
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Another QoL improvement to `log_effect_tree` — if you pass an array of
effects as the second argument, it will highlight them in the tree. It
will also italicise any effects that currently have the `INERT` flag.