diff --git a/.changeset/tasty-tires-wait.md b/.changeset/tasty-tires-wait.md new file mode 100644 index 0000000000..0f3fd2d671 --- /dev/null +++ b/.changeset/tasty-tires-wait.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: correctly coordinate component-level effects inside async blocks diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index 5bdba037b1..1bbda86fa7 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -20,7 +20,6 @@ import { EFFECT, DESTROYED, INERT, - REACTION_RAN, BLOCK_EFFECT, ROOT_EFFECT, EFFECT_TRANSPARENT, @@ -213,7 +212,11 @@ export function user_effect(fn) { // Non-nested `$effect(...)` in a component should be deferred // until the component is mounted var flags = /** @type {Effect} */ (active_effect).f; - var defer = !active_reaction && (flags & BRANCH_EFFECT) !== 0 && (flags & REACTION_RAN) === 0; + var defer = + !active_reaction && + (flags & BRANCH_EFFECT) !== 0 && + component_context !== null && + !component_context.i; if (defer) { // Top-level `$effect(...)` in an unmounted component — defer until mount diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-mount-timing/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-effect-mount-timing/Child.svelte new file mode 100644 index 0000000000..18856d71e1 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-mount-timing/Child.svelte @@ -0,0 +1,6 @@ + + +
diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-mount-timing/_config.js b/packages/svelte/tests/runtime-runes/samples/async-effect-mount-timing/_config.js new file mode 100644 index 0000000000..7a6e436825 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-mount-timing/_config.js @@ -0,0 +1,10 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + // Test that $effect/onMount etc at the top level of components are correctly deferred/coordinated if inside an async block + async test({ assert, logs }) { + await tick(); + assert.deepEqual(logs, [true]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-effect-mount-timing/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-effect-mount-timing/main.svelte new file mode 100644 index 0000000000..934d9d7f5b --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-effect-mount-timing/main.svelte @@ -0,0 +1,5 @@ + + +