Attachment in Async / Await Component not working
#16627
Development PRs
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
Alternative to #16721, partial alternative to #16709. Closes #16691, closes #16627, closes #16582 and #16651 as well.
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
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
System Info
svelte: 5.38.1
Severity
blocking all usage of svelte
Info
Async is active in the playground by default (but regardless in your repro you are still wrapping it with a boundary), let me check
I just came across this and made another repl: https://svelte.dev/playground/a94fa5d58eb94263bb812e61441d4774?version=5.38.6
This happens because schedule_effect is run for the attachment, which marks the root effect and its tree as dirty, but there's nothing that then flushes it, since the flush already happened earlier. Not sure what's the best way to fix it yet.