Skip to content

Commit b3c002a

Browse files
authored
fix: correctly compile $effect.root in svelte modules (#12315)
Fixes #12222
1 parent b2448dc commit b3c002a

File tree

5 files changed

+75
-1
lines changed

5 files changed

+75
-1
lines changed

.changeset/smart-fans-crash.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: correctly compile $effect.root in svelte modules

packages/svelte/src/compiler/phases/3-transform/server/transform-server.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,14 @@ const global_visitors = {
411411
return b.literal(false);
412412
}
413413

414+
if (rune === '$effect.root') {
415+
const args = /** @type {import('estree').Expression[]} */ (
416+
node.arguments.map((arg) => context.visit(arg))
417+
);
418+
// Just call the function directly
419+
return b.call(args[0]);
420+
}
421+
414422
if (rune === '$state.snapshot') {
415423
return /** @type {import('estree').Expression} */ (context.visit(node.arguments[0]));
416424
}
@@ -571,7 +579,7 @@ const javascript_visitors_runes = {
571579
for (const declarator of node.declarations) {
572580
const init = declarator.init;
573581
const rune = get_rune(init, state.scope);
574-
if (!rune || rune === '$effect.tracking' || rune === '$inspect') {
582+
if (!rune || rune === '$effect.tracking' || rune === '$inspect' || rune === '$effect.root') {
575583
declarations.push(/** @type {import('estree').VariableDeclarator} */ (visit(declarator)));
576584
continue;
577585
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
html: '<button>0</button><button>0</button><button>cleanup</button>',
6+
7+
async test({ assert, target, logs }) {
8+
const [b1, b2, b3] = target.querySelectorAll('button');
9+
10+
flushSync(() => {
11+
b1.click();
12+
b2.click();
13+
});
14+
15+
assert.deepEqual(logs, [0, 1]);
16+
17+
flushSync(() => {
18+
b3.click();
19+
});
20+
21+
assert.deepEqual(logs, [0, 1, 'cleanup 1', 'cleanup 2']);
22+
23+
flushSync(() => {
24+
b1.click();
25+
b2.click();
26+
});
27+
28+
assert.deepEqual(logs, [0, 1, 'cleanup 1', 'cleanup 2']);
29+
}
30+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script>
2+
import { with_root } from './root.svelte.js';
3+
let x = $state(0);
4+
let y = $state(0);
5+
6+
const cleanup = with_root(() => x)
7+
</script>
8+
9+
<button onclick={() => x++}>{x}</button>
10+
<button onclick={() => y++}>{y}</button>
11+
<button onclick={cleanup}>cleanup</button>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export function with_root(get_x) {
2+
const cleanup = $effect.root(() => {
3+
$effect(() => {
4+
console.log(get_x());
5+
});
6+
7+
const nested_cleanup = $effect.root(() => {
8+
return () => {
9+
console.log('cleanup 2');
10+
};
11+
});
12+
13+
return () => {
14+
console.log('cleanup 1');
15+
nested_cleanup();
16+
};
17+
});
18+
19+
return cleanup;
20+
}

0 commit comments

Comments
 (0)