Skip to content

Commit 8e2cc02

Browse files
committed
Merge branch 'gh-16548' into gh-16548-eager-block
2 parents c9b2654 + 87e5d00 commit 8e2cc02

File tree

23 files changed

+164
-95
lines changed

23 files changed

+164
-95
lines changed

.changeset/few-geese-itch.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: destroy dynamic component instance before creating new one

.changeset/itchy-games-guess.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: don't clone non-proxies in `$inspect`

.changeset/six-shirts-scream.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: avoid recursion error when tagging circular references

packages/svelte/src/internal/client/dev/inspect.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export function inspect(get_value, inspector = console.log) {
2626
return;
2727
}
2828

29-
var snap = snapshot(value, true);
29+
var snap = snapshot(value, true, true);
3030
untrack(() => {
3131
inspector(initial ? 'init' : 'update', ...snap);
3232
});

packages/svelte/src/internal/client/dom/blocks/svelte-component.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,6 @@ export function component(node, get_component, render_fn) {
3434
var pending_effect = null;
3535

3636
function commit() {
37-
if (effect) {
38-
pause_effect(effect);
39-
effect = null;
40-
}
41-
4237
if (offscreen_fragment) {
4338
// remove the anchor
4439
/** @type {Text} */ (offscreen_fragment.lastChild).remove();
@@ -56,6 +51,11 @@ export function component(node, get_component, render_fn) {
5651

5752
var defer = should_defer_append();
5853

54+
if (effect) {
55+
pause_effect(effect);
56+
effect = null;
57+
}
58+
5959
if (component) {
6060
var target = anchor;
6161

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,11 @@ export function proxy(value) {
9393

9494
/** Used in dev for $inspect.trace() */
9595
var path = '';
96-
96+
let updating = false;
9797
/** @param {string} new_path */
9898
function update_path(new_path) {
99+
if (updating) return;
100+
updating = true;
99101
path = new_path;
100102

101103
tag(version, `${path} version`);
@@ -104,6 +106,7 @@ export function proxy(value) {
104106
for (const [prop, source] of sources) {
105107
tag(source, get_label(path, prop));
106108
}
109+
updating = false;
107110
}
108111

109112
return new Proxy(/** @type {any} */ (value), {
@@ -284,13 +287,13 @@ export function proxy(value) {
284287
if (s === undefined) {
285288
if (!has || get_descriptor(target, prop)?.writable) {
286289
s = with_parent(() => source(undefined, stack));
287-
set(s, proxy(value));
288-
289-
sources.set(prop, s);
290290

291291
if (DEV) {
292292
tag(s, get_label(path, prop));
293293
}
294+
set(s, proxy(value));
295+
296+
sources.set(prop, s);
294297
}
295298
} else {
296299
has = s.v !== UNINITIALIZED;

packages/svelte/src/internal/shared/clone.js

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,15 @@ const empty = [];
1515
* @template T
1616
* @param {T} value
1717
* @param {boolean} [skip_warning]
18+
* @param {boolean} [no_tojson]
1819
* @returns {Snapshot<T>}
1920
*/
20-
export function snapshot(value, skip_warning = false) {
21+
export function snapshot(value, skip_warning = false, no_tojson = false) {
2122
if (DEV && !skip_warning) {
2223
/** @type {string[]} */
2324
const paths = [];
2425

25-
const copy = clone(value, new Map(), '', paths);
26+
const copy = clone(value, new Map(), '', paths, null, no_tojson);
2627
if (paths.length === 1 && paths[0] === '') {
2728
// value could not be cloned
2829
w.state_snapshot_uncloneable();
@@ -40,7 +41,7 @@ export function snapshot(value, skip_warning = false) {
4041
return copy;
4142
}
4243

43-
return clone(value, new Map(), '', empty);
44+
return clone(value, new Map(), '', empty, null, no_tojson);
4445
}
4546

4647
/**
@@ -49,10 +50,11 @@ export function snapshot(value, skip_warning = false) {
4950
* @param {Map<T, Snapshot<T>>} cloned
5051
* @param {string} path
5152
* @param {string[]} paths
52-
* @param {null | T} original The original value, if `value` was produced from a `toJSON` call
53+
* @param {null | T} [original] The original value, if `value` was produced from a `toJSON` call
54+
* @param {boolean} [no_tojson]
5355
* @returns {Snapshot<T>}
5456
*/
55-
function clone(value, cloned, path, paths, original = null) {
57+
function clone(value, cloned, path, paths, original = null, no_tojson = false) {
5658
if (typeof value === 'object' && value !== null) {
5759
var unwrapped = cloned.get(value);
5860
if (unwrapped !== undefined) return unwrapped;
@@ -71,7 +73,7 @@ function clone(value, cloned, path, paths, original = null) {
7173
for (var i = 0; i < value.length; i += 1) {
7274
var element = value[i];
7375
if (i in value) {
74-
copy[i] = clone(element, cloned, DEV ? `${path}[${i}]` : path, paths);
76+
copy[i] = clone(element, cloned, DEV ? `${path}[${i}]` : path, paths, null, no_tojson);
7577
}
7678
}
7779

@@ -88,8 +90,15 @@ function clone(value, cloned, path, paths, original = null) {
8890
}
8991

9092
for (var key in value) {
91-
// @ts-expect-error
92-
copy[key] = clone(value[key], cloned, DEV ? `${path}.${key}` : path, paths);
93+
copy[key] = clone(
94+
// @ts-expect-error
95+
value[key],
96+
cloned,
97+
DEV ? `${path}.${key}` : path,
98+
paths,
99+
null,
100+
no_tojson
101+
);
93102
}
94103

95104
return copy;
@@ -99,7 +108,7 @@ function clone(value, cloned, path, paths, original = null) {
99108
return /** @type {Snapshot<T>} */ (structuredClone(value));
100109
}
101110

102-
if (typeof (/** @type {T & { toJSON?: any } } */ (value).toJSON) === 'function') {
111+
if (typeof (/** @type {T & { toJSON?: any } } */ (value).toJSON) === 'function' && !no_tojson) {
103112
return clone(
104113
/** @type {T & { toJSON(): any } } */ (value).toJSON(),
105114
cloned,
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script>
2+
$effect.pre(() => {
3+
console.log('create A');
4+
return () => console.log('destroy A');
5+
});
6+
</script>
7+
8+
<h1>A</h1>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script>
2+
$effect.pre(() => {
3+
console.log('create B');
4+
return () => console.log('destroy B');
5+
});
6+
</script>
7+
8+
<h1>B</h1>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { test } from '../../test';
2+
import { flushSync } from 'svelte';
3+
4+
export default test({
5+
mode: ['client', 'hydrate'],
6+
7+
async test({ assert, target, logs }) {
8+
const [button] = target.querySelectorAll('button');
9+
10+
flushSync(() => button.click());
11+
assert.deepEqual(logs, ['create A', 'destroy A', 'create B']);
12+
}
13+
});

0 commit comments

Comments
 (0)