diff --git a/.changeset/silent-teeth-invent.md b/.changeset/silent-teeth-invent.md new file mode 100644 index 0000000000..54603cc27e --- /dev/null +++ b/.changeset/silent-teeth-invent.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure eager effects don't break reactions chain diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js index 8ae406b57b..052ca97dc0 100644 --- a/packages/svelte/src/internal/client/reactivity/sources.js +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -14,7 +14,9 @@ import { is_dirty, untracking, is_destroying_effect, - push_reaction_value + push_reaction_value, + set_is_updating_effect, + is_updating_effect } from '../runtime.js'; import { equals, safe_equals } from './equality.js'; import { @@ -246,19 +248,25 @@ export function internal_set(source, value) { export function flush_eager_effects() { eager_effects_deferred = false; + var prev_is_updating_effect = is_updating_effect; + set_is_updating_effect(true); const inspects = Array.from(eager_effects); - for (const effect of inspects) { - // Mark clean inspect-effects as maybe dirty and then check their dirtiness - // instead of just updating the effects - this way we avoid overfiring. - if ((effect.f & CLEAN) !== 0) { - set_signal_status(effect, MAYBE_DIRTY); - } + try { + for (const effect of inspects) { + // Mark clean inspect-effects as maybe dirty and then check their dirtiness + // instead of just updating the effects - this way we avoid overfiring. + if ((effect.f & CLEAN) !== 0) { + set_signal_status(effect, MAYBE_DIRTY); + } - if (is_dirty(effect)) { - update_effect(effect); + if (is_dirty(effect)) { + update_effect(effect); + } } + } finally { + set_is_updating_effect(prev_is_updating_effect); } eager_effects.clear(); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-derived-4/_config.js b/packages/svelte/tests/runtime-runes/samples/inspect-derived-4/_config.js new file mode 100644 index 0000000000..3a3bca7221 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/inspect-derived-4/_config.js @@ -0,0 +1,35 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; +import { normalise_inspect_logs } from '../../../helpers'; + +export default test({ + compileOptions: { + dev: true + }, + + async test({ assert, target, logs }) { + const [b] = target.querySelectorAll('button'); + + b.click(); + await tick(); + assert.htmlEqual(target.innerHTML, ``); + + b.click(); + await tick(); + assert.htmlEqual(target.innerHTML, ``); + + b.click(); + await tick(); + assert.htmlEqual(target.innerHTML, ``); + + assert.deepEqual(normalise_inspect_logs(logs), [ + [0, 1, 2], + [1, 2], + 'at SvelteSet.add', + [2], + 'at SvelteSet.add', + [], + 'at SvelteSet.add' + ]); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/inspect-derived-4/main.svelte b/packages/svelte/tests/runtime-runes/samples/inspect-derived-4/main.svelte new file mode 100644 index 0000000000..eb4ea891db --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/inspect-derived-4/main.svelte @@ -0,0 +1,14 @@ + + +