diff --git a/.changeset/kind-dots-sort.md b/.changeset/kind-dots-sort.md new file mode 100644 index 0000000000..532b994a7f --- /dev/null +++ b/.changeset/kind-dots-sort.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: remove memory leak diff --git a/.changeset/real-pandas-brush.md b/.changeset/real-pandas-brush.md new file mode 100644 index 0000000000..4f92cf1af1 --- /dev/null +++ b/.changeset/real-pandas-brush.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: call beforeUpdate/afterUpdate callbacks when props are mutated diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 2bfe23ce3e..47547636e1 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -1308,7 +1308,6 @@ export function derived(init) { create_computation_signal(flags | CLEAN, UNINITIALIZED, current_block) ); signal.i = init; - bind_signal_to_component_context(signal); signal.e = default_equals; if (current_consumer !== null) { push_reference(current_consumer, signal); @@ -1335,26 +1334,7 @@ export function derived_safe_equal(init) { */ /*#__NO_SIDE_EFFECTS__*/ export function source(initial_value) { - const source = create_source_signal(SOURCE | CLEAN, initial_value); - bind_signal_to_component_context(source); - return source; -} - -/** - * This function binds a signal to the component context, so that we can fire - * beforeUpdate/afterUpdate callbacks at the correct time etc - * @param {import('./types.js').Signal} signal - */ -function bind_signal_to_component_context(signal) { - if (current_component_context === null || !current_component_context.r) return; - - const signals = current_component_context.d; - - if (signals) { - signals.push(signal); - } else { - current_component_context.d = [signal]; - } + return create_source_signal(SOURCE | CLEAN, initial_value); } /** @@ -1366,6 +1346,13 @@ function bind_signal_to_component_context(signal) { export function mutable_source(initial_value) { const s = source(initial_value); s.e = safe_equal; + + // bind the signal to the component context, in case we need to + // track updates to trigger beforeUpdate/afterUpdate callbacks + if (current_component_context) { + (current_component_context.d ??= []).push(s); + } + return s; } @@ -1974,10 +1961,7 @@ function observe_all(context) { for (const signal of context.d) get(signal); } - const props = get_descriptors(context.s); - for (const descriptor of Object.values(props)) { - if (descriptor.get) descriptor.get(); - } + deep_read(context.s); } /** diff --git a/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/Child.svelte b/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/Child.svelte new file mode 100644 index 0000000000..9841295830 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/Child.svelte @@ -0,0 +1,12 @@ + + + diff --git a/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/_config.js b/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/_config.js new file mode 100644 index 0000000000..aa42c2a2d6 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/_config.js @@ -0,0 +1,20 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { logs } from './logs.js'; + +export default test({ + html: ``, + + test({ assert, target }) { + const btn = target.querySelector('button'); + + flushSync(() => btn?.click()); + + assert.htmlEqual(target.innerHTML, ``); + assert.deepEqual(logs, ['changed', 'changed']); + }, + + after_test() { + logs.length = 0; + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/logs.js b/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/logs.js new file mode 100644 index 0000000000..8c8a1318cb --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/logs.js @@ -0,0 +1,2 @@ +/** @type {any[]} */ +export const logs = []; diff --git a/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/main.svelte b/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/main.svelte new file mode 100644 index 0000000000..6e91de5841 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/before-update-in-legacy-child/main.svelte @@ -0,0 +1,10 @@ + + + + +