fix: skip rebase logic in non-async mode (#18040)

Fixes part of #17940 (the hydration->error thing still needs a repro).
Essentially in sync mode render effects are executed during traversing
the effect tree, and when flushSync is called during that it can cause
the timing of things getting out of sync such that you end up wanting to
rebase another branch, which is never needed in sync mode.

So we just skip that logic in sync mode. Another way would be to adjust
flushSync such that it does appends itself to the end of the current
flushing cycle if it notices processing is already ongoing. This will
not work when you pass a callback function to `flushSync` though -
another indicator that we should probably remove that callback argument.

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
Co-authored-by: Rich Harris <hello@rich-harris.dev>
pull/18073/head
Simon H 2 weeks ago committed by GitHub
parent adba758067
commit d86cb5cc32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: skip rebase logic in non-async mode

@ -349,7 +349,9 @@ export class Batch {
next_batch.#process();
}
if (!batches.has(this)) {
// In sync mode flushSync can cause #commit to wrongfully think that there needs to be a rebase, so we only do it in async mode
// TODO fix the underlying cause, otherwise this will likely regress when non-async mode is removed
if (async_mode_flag && !batches.has(this)) {
this.#commit();
}
}
@ -791,6 +793,7 @@ export class Batch {
}
}
// TODO Svelte@6 think about removing the callback argument.
/**
* Synchronously flush any pending updates.
* Returns void if no callback is provided, otherwise returns the result of calling the callback.

@ -0,0 +1,8 @@
<svelte:options customElement={{
tag: "my-inner",
props: { value: { reflect: true }}
}} />
<script>
export let value;
</script>
{value}

@ -0,0 +1,20 @@
import { tick } from 'svelte';
import { test } from '../../test';
export default test({
async test({ assert, target }) {
await tick();
const [btn] = target.querySelectorAll('button');
btn.click();
await tick();
assert.htmlEqual(
target.innerHTML,
`
<button>inc</button>
<my-inner value="2"></my-inner>
2
`
);
}
});

@ -0,0 +1,12 @@
<script>
import "./Inner.svelte"
let count = 1;
</script>
<button on:click={() => count++}>inc</button>
<!-- updating value prop will cause a flushSync -->
<my-inner value={count}></my-inner>
<!-- updating count will cause an internal_set -->
{#each [count] as row}
{row}
{/each}
Loading…
Cancel
Save