fix: correct first processing of boundary with pending snippet
#16709
Closing issue
Describe the bug
In my App (in Dev Mode) i experienced that my attachement didn't trigger when the node was added to the DOM. Only after the component refreshed ( from HMR i guess ) the attachment triggered and in my case rendered a map.
I have a small repl where it doesn't work either but i don't know if async is activated on the Svelte Playground. Maybe this is the expected output and i'm doing something wrong in the repl.
Thanks for your help ♥️
Reproduction
https://svelte.dev/playground/8fe0eb6dbe8943b5ba057de9b6259ecb?version=latest
System Info
svelte: 5.38.1
Severity
blocking all usage of svelte
Pull request
Fixes #16627
This adjusts the logic of the first processing of an async boundary: Previously, it would only increment/decrement the pending count of a batch on subsequent runs and otherwise deactivate the batch, but this has multiple problems:
- batches will get deactivated, and so certain changes (like chains of top level async deriveds) would create multiple batches, which is wrong. They should all be associated with the same batch
- while async work is happening, the scheduled flush of the batch runs, and will run any
$effects that were already picked up, because from its point of view there is no pending work
Additionally, currently after async work has finished which causes more effects (from within attachments, or top level $effects after async work) to be created this effects are never run because they are marked as dirty, but there's no flush scheduled.
The fix is
to always increment/decrement the pending countUpdate: Turns out this was on purpose, so we gotta keep not incrementing/decrementing on pending boundaries, else a state change that has causes a pending boundary to appear will be deferred which we don't want, since the async work happens "hidden" behind the pending boundary; added a test. We need to solve this differently by not collecting these effects until all async work is done- to run the flush work in a decrement in a microtask to give room for subsequent effects to be created and picked up (done, this fixes #16627)
- to properly assign component
$effects to the component context (todo)
This also cleans up our scheduling system - everything goes through queue_micro_task now, before this change batching was always in microtasks (meaning flushSync wouldn't really work correctly) and in some weird order (LIFO insteand of FIFO), and flushSync didn't take into account pending tasks.
There's some tests failing. One of them needs #16698 merged first, another one needs #16621 (that test was always failing when you tried it in the playground, weirdly the test passed up until now for some reason). The remaining need investigation.
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
- Prefix your PR title with
feat:,fix:,chore:, ordocs:. - 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
- Run the tests with
pnpm testand lint the project withpnpm lint
Info
🦋 Changeset detected
Latest commit: 03f6287
The changes in this PR will be included in the next version bump.
This PR includes changesets to release 1 package
| Name | Type |
|---|---|
| svelte | 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
pnpm add https://pkg.pr.new/svelte@16709fix: correct first processing of boundary with pending snippet
• Sep 3, 2025, 9:51 PMWIP
detect async_deriveds inside batches that are destroyed in later batches
• Sep 5, 2025, 3:02 PM