Skip to content

Commit 139114b

Browse files
authored
fix: ensure legacy run utility does not cause cycles (#13643)
* fix: ensure legacy run utility does not cause cycles * add warning * add warning * lint * feedback * lint * lint
1 parent ffa2af7 commit 139114b

File tree

5 files changed

+45
-2
lines changed

5 files changed

+45
-2
lines changed

.changeset/moody-pugs-tan.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: ensure legacy run utility does not cause cycles

documentation/docs/98-reference/.generated/client-warnings.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ Hydration failed because the initial UI does not match what was rendered on the
5656
The `render` function passed to `createRawSnippet` should return HTML for a single element
5757
```
5858

59+
### legacy_recursive_reactive_block
60+
61+
```
62+
Detected a migrated `$:` reactive block that both accesses and updates the same reactive value. This may cause recursive updates when converted to an `$effect`.
63+
```
64+
5965
### lifecycle_double_unmount
6066

6167
```

packages/svelte/messages/client-warnings/warnings.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ The easiest way to log a value as it changes over time is to use the [`$inspect`
3636

3737
> The `render` function passed to `createRawSnippet` should return HTML for a single element
3838
39+
## legacy_recursive_reactive_block
40+
41+
> Detected a migrated `$:` reactive block that both accesses and updates the same reactive value. This may cause recursive updates when converted to an `$effect`.
42+
3943
## lifecycle_double_unmount
4044

4145
> Tried to unmount a component that was not mounted

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,18 @@ export function invalid_raw_snippet_render() {
9999
}
100100
}
101101

102+
/**
103+
* Detected a migrated `$:` reactive block that both accesses and updates the same reactive value. This may cause recursive updates when converted to an `$effect`.
104+
*/
105+
export function legacy_recursive_reactive_block() {
106+
if (DEV) {
107+
console.warn(`%c[svelte] legacy_recursive_reactive_block\n%cDetected a migrated \`$:\` reactive block that both accesses and updates the same reactive value. This may cause recursive updates when converted to an \`$effect\`.`, bold, normal);
108+
} else {
109+
// TODO print a link to the documentation
110+
console.warn("legacy_recursive_reactive_block");
111+
}
112+
}
113+
102114
/**
103115
* Tried to unmount a component that was not mounted
104116
*/

packages/svelte/src/legacy/legacy-client.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
/** @import { ComponentConstructorOptions, ComponentType, SvelteComponent, Component } from 'svelte' */
2+
import { DIRTY, MAYBE_DIRTY } from '../internal/client/constants.js';
23
import { user_pre_effect } from '../internal/client/reactivity/effects.js';
34
import { mutable_source, set } from '../internal/client/reactivity/sources.js';
45
import { hydrate, mount, unmount } from '../internal/client/render.js';
5-
import { component_context, flush_sync, get } from '../internal/client/runtime.js';
6+
import {
7+
active_effect,
8+
component_context,
9+
flush_sync,
10+
get,
11+
set_signal_status
12+
} from '../internal/client/runtime.js';
613
import { lifecycle_outside_component } from '../internal/shared/errors.js';
714
import { define_property, is_array } from '../internal/shared/utils.js';
15+
import * as w from '../internal/client/warnings.js';
816

917
/**
1018
* Takes the same options as a Svelte 4 component and the component function and returns a Svelte 4 compatible component.
@@ -169,7 +177,15 @@ class Svelte4Component {
169177
* @returns {void}
170178
*/
171179
export function run(fn) {
172-
user_pre_effect(fn);
180+
user_pre_effect(() => {
181+
fn();
182+
var effect = /** @type {import('#client').Effect} */ (active_effect);
183+
// If the effect is immediately made dirty again, mark it as maybe dirty to emulate legacy behaviour
184+
if ((effect.f & DIRTY) !== 0) {
185+
w.legacy_recursive_reactive_block();
186+
set_signal_status(effect, MAYBE_DIRTY);
187+
}
188+
});
173189
}
174190

175191
/**

0 commit comments

Comments
 (0)