Skip to content

Commit fb6b40a

Browse files
committed
fix: don't fail on flushSync while flushing effects
WIP fixes #16640
1 parent 5912754 commit fb6b40a

File tree

6 files changed

+41
-6
lines changed

6 files changed

+41
-6
lines changed

.changeset/honest-coins-work.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 fail on `flushSync` while flushing effects

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ export class Batch {
187187
// if there are multiple batches, we are 'time travelling' —
188188
// we need to undo the changes belonging to any batch
189189
// other than the current one
190+
// TODO this is wrong when flushSync is called while another batch is active, can be two when there's actually no time traveling
190191
if (batches.size > 1) {
191192
current_values = new Map();
192193
batch_deriveds = new Map();
@@ -484,7 +485,8 @@ export class Batch {
484485
*/
485486
export function flushSync(fn) {
486487
if (async_mode_flag && active_effect !== null) {
487-
e.flush_sync_in_effect();
488+
// TODO why do we disallow this?
489+
// e.flush_sync_in_effect();
488490
}
489491

490492
var was_flushing_sync = is_flushing_sync;
@@ -622,7 +624,9 @@ function flush_queued_effects(effects) {
622624
}
623625
}
624626

625-
if (eager_block_effects.length > 0) {
627+
// If update_effect() has a flushSync() in it, we may have flushed another flush_queued_effects(),
628+
// which already handled this logic and did set eager_block_effects to null.
629+
if (eager_block_effects?.length > 0) {
626630
// TODO this feels incorrect! it gets the tests passing
627631
old_values.clear();
628632

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import * as w from '../internal/client/warnings.js';
1111
import { DEV } from 'esm-env';
1212
import { FILENAME } from '../constants.js';
1313
import { component_context, dev_current_component_function } from '../internal/client/context.js';
14-
import { async_mode_flag } from '../internal/flags/index.js';
1514

1615
/**
1716
* Takes the same options as a Svelte 4 component and the component function and returns a Svelte 4 compatible component.
@@ -121,9 +120,8 @@ class Svelte4Component {
121120
recover: options.recover
122121
});
123122

124-
// We don't flushSync for custom element wrappers or if the user doesn't want it,
125-
// or if we're in async mode since `flushSync()` will fail
126-
if (!async_mode_flag && (!options?.props?.$$host || options.sync === false)) {
123+
// We don't flushSync for custom element wrappers or if the user doesn't want it
124+
if (!options?.props?.$$host || options.sync === false) {
127125
flushSync();
128126
}
129127

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<script>
2+
let { text } = $props();
3+
4+
$effect(() => console.log(text));
5+
</script>
6+
7+
{text}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
async test({ assert, target, logs }) {
5+
assert.htmlEqual(target.innerHTML, `<button>show</button> <div>hello</div>`);
6+
assert.deepEqual(logs, ['hello']);
7+
}
8+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script>
2+
import { flushSync, mount } from 'svelte'
3+
import Child from './Child.svelte';
4+
5+
let show = $state(false);
6+
</script>
7+
8+
<button onclick={() => show = true}>show</button>
9+
10+
<div {@attach (target) => {
11+
mount(Child, { target, props: { text: 'hello' } });
12+
flushSync();
13+
}}></div>

0 commit comments

Comments
 (0)