Skip to content

Commit 96eae28

Browse files
authored
fix: remove memory leak, make beforeUpdate etc work correctly (#10570)
* fix: remove memory leak * changeset * mutable_source is only used in non-runes mode, no need to check here * simplify * oops --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 662eda4 commit 96eae28

File tree

7 files changed

+63
-25
lines changed

7 files changed

+63
-25
lines changed

.changeset/kind-dots-sort.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: remove memory leak

.changeset/real-pandas-brush.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: call beforeUpdate/afterUpdate callbacks when props are mutated

packages/svelte/src/internal/client/runtime.js

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,7 +1308,6 @@ export function derived(init) {
13081308
create_computation_signal(flags | CLEAN, UNINITIALIZED, current_block)
13091309
);
13101310
signal.i = init;
1311-
bind_signal_to_component_context(signal);
13121311
signal.e = default_equals;
13131312
if (current_consumer !== null) {
13141313
push_reference(current_consumer, signal);
@@ -1335,26 +1334,7 @@ export function derived_safe_equal(init) {
13351334
*/
13361335
/*#__NO_SIDE_EFFECTS__*/
13371336
export function source(initial_value) {
1338-
const source = create_source_signal(SOURCE | CLEAN, initial_value);
1339-
bind_signal_to_component_context(source);
1340-
return source;
1341-
}
1342-
1343-
/**
1344-
* This function binds a signal to the component context, so that we can fire
1345-
* beforeUpdate/afterUpdate callbacks at the correct time etc
1346-
* @param {import('./types.js').Signal} signal
1347-
*/
1348-
function bind_signal_to_component_context(signal) {
1349-
if (current_component_context === null || !current_component_context.r) return;
1350-
1351-
const signals = current_component_context.d;
1352-
1353-
if (signals) {
1354-
signals.push(signal);
1355-
} else {
1356-
current_component_context.d = [signal];
1357-
}
1337+
return create_source_signal(SOURCE | CLEAN, initial_value);
13581338
}
13591339

13601340
/**
@@ -1366,6 +1346,13 @@ function bind_signal_to_component_context(signal) {
13661346
export function mutable_source(initial_value) {
13671347
const s = source(initial_value);
13681348
s.e = safe_equal;
1349+
1350+
// bind the signal to the component context, in case we need to
1351+
// track updates to trigger beforeUpdate/afterUpdate callbacks
1352+
if (current_component_context) {
1353+
(current_component_context.d ??= []).push(s);
1354+
}
1355+
13691356
return s;
13701357
}
13711358

@@ -1974,10 +1961,7 @@ function observe_all(context) {
19741961
for (const signal of context.d) get(signal);
19751962
}
19761963

1977-
const props = get_descriptors(context.s);
1978-
for (const descriptor of Object.values(props)) {
1979-
if (descriptor.get) descriptor.get();
1980-
}
1964+
deep_read(context.s);
19811965
}
19821966

19831967
/**
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<svelte:options runes={false} />
2+
3+
<script>
4+
import { beforeUpdate } from 'svelte';
5+
import { logs } from './logs.js'
6+
7+
export let object;
8+
9+
beforeUpdate(() => {
10+
logs.push('changed');
11+
});
12+
</script>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
import { logs } from './logs.js';
4+
5+
export default test({
6+
html: `<button>clicks: 0</button>`,
7+
8+
test({ assert, target }) {
9+
const btn = target.querySelector('button');
10+
11+
flushSync(() => btn?.click());
12+
13+
assert.htmlEqual(target.innerHTML, `<button>clicks: 1</button>`);
14+
assert.deepEqual(logs, ['changed', 'changed']);
15+
},
16+
17+
after_test() {
18+
logs.length = 0;
19+
}
20+
});
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/** @type {any[]} */
2+
export const logs = [];
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script>
2+
import Child from './Child.svelte';
3+
let object = $state({ count: 0 })
4+
</script>
5+
6+
<button onclick={() => object.count += 1}>
7+
clicks: {object.count}
8+
</button>
9+
10+
<Child {object} />

0 commit comments

Comments
 (0)