From 498a696ac8042153d7d564ea5ce78dfe8268cc71 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 13 Oct 2026 12:07:21 -0400 Subject: [PATCH] restore updating content.wv on fork commit apply() uses the batch's recorded write versions while other batches are pending, so they must match the fresh versions given to the sources on commit. --- .../src/internal/client/reactivity/batch.js | 2 +- .../async-fork-commit-new-reader/_config.js | 35 +++++++++++++++++++ .../async-fork-commit-new-reader/main.svelte | 25 +++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 packages/svelte/tests/runtime-runes/samples/async-fork-commit-new-reader/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/async-fork-commit-new-reader/main.svelte diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 2569acb897..d7e4dbbe00 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -1431,7 +1431,7 @@ export function fork(fn) { // apply changes and update write versions so deriveds see the change for (var [source, content] of batch.current) { source.v = content.v; - source.wv = increment_write_version(); + content.wv = source.wv = increment_write_version(); } // trigger any `$state.eager(...)` expressions with the new state. diff --git a/packages/svelte/tests/runtime-runes/samples/async-fork-commit-new-reader/_config.js b/packages/svelte/tests/runtime-runes/samples/async-fork-commit-new-reader/_config.js new file mode 100644 index 0000000000..a9e860bec7 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-fork-commit-new-reader/_config.js @@ -0,0 +1,35 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +const buttons = + ''; + +// The template effect is deferred by the fork (it depends on `s` via `big`), but before the +// fork is committed, it re-runs in the real world and starts reading `s` directly. +// Committing the fork (while another batch is pending) must still update it. +export default test({ + async test({ assert, target }) { + await tick(); + const [u, f, cond, commit, shift] = target.querySelectorAll('button'); + + // unrelated pending batch + u.click(); + await tick(); + + f.click(); + await tick(); + assert.htmlEqual(target.innerHTML, `${buttons}

0

false

`); + + cond.click(); + await tick(); + assert.htmlEqual(target.innerHTML, `${buttons}

0

0

`); + + commit.click(); + await tick(); + assert.htmlEqual(target.innerHTML, `${buttons}

0

1

`); + + shift.click(); + await tick(); + assert.htmlEqual(target.innerHTML, `${buttons}

1

1

`); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-fork-commit-new-reader/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-fork-commit-new-reader/main.svelte new file mode 100644 index 0000000000..a52d6b4dfd --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-fork-commit-new-reader/main.svelte @@ -0,0 +1,25 @@ + + + + + + + + +

{await push(u)}

+

{cond ? s : big}