diff --git a/.changeset/kind-schools-share.md b/.changeset/kind-schools-share.md new file mode 100644 index 000000000000..cf052c12bbd3 --- /dev/null +++ b/.changeset/kind-schools-share.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure component root effect updates occur first diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js index 28589ce94df1..ac08d738386b 100644 --- a/packages/svelte/src/internal/client/reactivity/effects.js +++ b/packages/svelte/src/internal/client/reactivity/effects.js @@ -32,7 +32,8 @@ import { HEAD_EFFECT, MAYBE_DIRTY, EFFECT_HAS_DERIVED, - BOUNDARY_EFFECT + BOUNDARY_EFFECT, + DISCONNECTED } from '../constants.js'; import { set } from './sources.js'; import * as e from '../errors.js'; @@ -229,7 +230,7 @@ export function inspect_effect(fn) { * @returns {() => void} */ export function effect_root(fn) { - const effect = create_effect(ROOT_EFFECT, fn, true); + const effect = create_effect(ROOT_EFFECT | DISCONNECTED, fn, true); return () => { destroy_effect(effect); diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 486c819f3671..3105df06fcc2 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -738,7 +738,14 @@ export function schedule_effect(signal) { } } - queued_root_effects.push(effect); + // Schedule the root effect for component trees first so any updates + // that affect the component tree occur first. Root effects that are + // not for component trees (i.e. $effect.root) will be marked as disconnected + if ((effect.f & DISCONNECTED) === 0) { + queued_root_effects.unshift(effect); + } else { + queued_root_effects.push(effect); + } } /** diff --git a/packages/svelte/tests/runtime-runes/samples/toStore-teardown/_config.js b/packages/svelte/tests/runtime-runes/samples/toStore-teardown/_config.js new file mode 100644 index 000000000000..95904f011fc0 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/toStore-teardown/_config.js @@ -0,0 +1,13 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + let [, btn2] = target.querySelectorAll('button'); + + btn2.click(); + flushSync(); + + assert.htmlEqual(target.innerHTML, ``); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/toStore-teardown/child.svelte b/packages/svelte/tests/runtime-runes/samples/toStore-teardown/child.svelte new file mode 100644 index 000000000000..f1b1b7b49769 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/toStore-teardown/child.svelte @@ -0,0 +1,11 @@ + + +

+ Current value: + {$currentValue} +

diff --git a/packages/svelte/tests/runtime-runes/samples/toStore-teardown/main.svelte b/packages/svelte/tests/runtime-runes/samples/toStore-teardown/main.svelte new file mode 100644 index 000000000000..7d36dd95cbfd --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/toStore-teardown/main.svelte @@ -0,0 +1,15 @@ + + + + + +{#if data} + +{/if}