Skip to content

Commit 7105736

Browse files
authored
fix: restore batch along with effect context (#16668)
Fixes #16596 Fixes sveltejs/kit#14124
1 parent 57fed6a commit 7105736

File tree

12 files changed

+188
-3
lines changed

12 files changed

+188
-3
lines changed

.changeset/silent-pigs-relax.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: restore batch along with effect context

packages/svelte/src/internal/client/reactivity/async.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,13 @@ function capture() {
7373
var previous_effect = active_effect;
7474
var previous_reaction = active_reaction;
7575
var previous_component_context = component_context;
76+
var previous_batch = current_batch;
7677

7778
return function restore() {
7879
set_active_effect(previous_effect);
7980
set_active_reaction(previous_reaction);
8081
set_component_context(previous_component_context);
82+
previous_batch?.activate();
8183

8284
if (DEV) {
8385
set_from_async_derived(null);
@@ -176,8 +178,8 @@ export function unset_context() {
176178
* @param {() => Promise<void>} fn
177179
*/
178180
export async function async_body(fn) {
179-
const unsuspend = suspend();
180-
const active = /** @type {Effect} */ (active_effect);
181+
var unsuspend = suspend();
182+
var active = /** @type {Effect} */ (active_effect);
181183

182184
try {
183185
await fn();

packages/svelte/src/internal/client/reactivity/batch.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ let queued_root_effects = [];
7676
let last_scheduled_effect = null;
7777

7878
let is_flushing = false;
79-
8079
let is_flushing_sync = false;
80+
8181
export class Batch {
8282
/**
8383
* The current values of any sources that are updated in this batch
@@ -678,6 +678,8 @@ export function suspend() {
678678
if (!pending) {
679679
batch.activate();
680680
batch.decrement();
681+
} else {
682+
batch.deactivate();
681683
}
682684

683685
unset_context();
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script lang="ts">
2+
import { resolve } from './main.svelte';
3+
4+
const bar = await new Promise((r) => resolve.push(() => r('bar')));
5+
</script>
6+
7+
<p>bar: {bar}</p>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script lang="ts">
2+
import { resolve } from './main.svelte';
3+
import Bar from './Bar.svelte';
4+
5+
const foo = await new Promise((r) => resolve.push(() => r('foo')));
6+
</script>
7+
8+
<p>foo: {foo}</p>
9+
10+
<Bar/>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { tick } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
async test({ assert, target }) {
6+
const [show, resolve] = target.querySelectorAll('button');
7+
8+
show.click();
9+
await tick();
10+
assert.htmlEqual(
11+
target.innerHTML,
12+
`
13+
<button>show</button>
14+
<button>resolve</button>
15+
<p>pending...</p>
16+
`
17+
);
18+
19+
resolve.click();
20+
await tick();
21+
assert.htmlEqual(
22+
target.innerHTML,
23+
`
24+
<button>show</button>
25+
<button>resolve</button>
26+
<p>pending...</p>
27+
`
28+
);
29+
30+
resolve.click();
31+
await tick();
32+
assert.htmlEqual(
33+
target.innerHTML,
34+
`
35+
<button>show</button>
36+
<button>resolve</button>
37+
<p>foo: foo</p>
38+
<p>bar: bar</p>
39+
`
40+
);
41+
}
42+
});
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<script module>
2+
export let resolve = [];
3+
</script>
4+
5+
<script>
6+
import Foo from './Foo.svelte';
7+
8+
let show = $state(false);
9+
</script>
10+
11+
<button onclick={() => show = true}>
12+
show
13+
</button>
14+
15+
<button onclick={() => resolve.shift()()}>
16+
resolve
17+
</button>
18+
19+
<svelte:boundary>
20+
{#if show}
21+
<Foo/>
22+
{/if}
23+
24+
{#if $effect.pending()}
25+
<p>pending...</p>
26+
{/if}
27+
28+
{#snippet pending()}
29+
<p>initializing...</p>
30+
{/snippet}
31+
</svelte:boundary>

packages/svelte/tests/runtime-runes/samples/async-redirect/_config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export default test({
2929
<button>c</button>
3030
<button>ok</button>
3131
<p>c</p>
32+
<p>b or c</p>
3233
`
3334
);
3435

@@ -46,6 +47,7 @@ export default test({
4647
<button>c</button>
4748
<button>ok</button>
4849
<p>b</p>
50+
<p>b or c</p>
4951
`
5052
);
5153
}

packages/svelte/tests/runtime-runes/samples/async-redirect/main.svelte

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@
3333
<p>c</p>
3434
{/if}
3535

36+
{#if route === 'b' || route === 'c'}
37+
<p>b or c</p>
38+
{/if}
39+
3640
{#snippet pending()}
3741
<p>pending...</p>
3842
{/snippet}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script lang="ts">
2+
import { resolve } from './main.svelte';
3+
4+
const foo = $derived(await new Promise((r) => resolve.push(() => r('foo'))));
5+
const bar = $derived(await new Promise((r) => resolve.push(() => r('bar'))));
6+
</script>
7+
8+
<p>{foo} {bar}</p>

0 commit comments

Comments
 (0)