From da2f83343bf5e2fb183881b74ef06fac24f0e249 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Thu, 24 Sep 2026 22:47:52 +0200 Subject: [PATCH 1/2] fix: read batch-local array on each-block commit (#18879) Another extraction from #18861 which I'm pretty sure you can also construct a buggy reproduction for today, but with #18861 it's strictly necessary so we don't need to come up with one now --- .changeset/short-radios-sneeze.md | 5 +++++ packages/svelte/src/internal/client/dom/blocks/each.js | 10 ++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 .changeset/short-radios-sneeze.md diff --git a/.changeset/short-radios-sneeze.md b/.changeset/short-radios-sneeze.md new file mode 100644 index 0000000000..847c3eef17 --- /dev/null +++ b/.changeset/short-radios-sneeze.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: read batch-local array on each-block commit diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js index ea828f893b..58d59a6825 100644 --- a/packages/svelte/src/internal/client/dom/blocks/each.js +++ b/packages/svelte/src/internal/client/dom/blocks/each.js @@ -216,9 +216,6 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f tag(each_array, '{#each ...}'); } - /** @type {V[]} */ - var array; - /** @type {Map>} */ var pending = new Map(); @@ -234,6 +231,11 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f state.pending.delete(batch); + // The effect doesn't necessarily re-run in a batch right before that batch commits + // (its view of the collection may not have changed), so we read the collection + // as the committing batch sees it rather than using the most recent block run's result + var array = get(each_array); + state.fallback = fallback; reconcile(state, array, anchor, flags, get_key); @@ -264,7 +266,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f } var effect = block(() => { - array = /** @type {V[]} */ (get(each_array)); + var array = /** @type {V[]} */ (get(each_array)); var length = array.length; /** `true` if there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */ From 98e547535d9286cfd4163fe3a6d85c7053db6c6e Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Thu, 24 Sep 2026 22:49:15 +0200 Subject: [PATCH 2/2] fix: flush anything pending before invoking flushSync callback function (#18878) no new test here but it's necessary for #18861 to work, and we might as well extract it --- .changeset/major-papayas-run.md | 5 +++++ .../svelte/src/internal/client/reactivity/batch.js | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 .changeset/major-papayas-run.md diff --git a/.changeset/major-papayas-run.md b/.changeset/major-papayas-run.md new file mode 100644 index 0000000000..59909fb448 --- /dev/null +++ b/.changeset/major-papayas-run.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: flush anything pending before invoking flushSync callback function diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index f620c2b4c8..05f7586072 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -1032,15 +1032,15 @@ export class Batch { */ export function flushSync(fn) { var was_flushing_sync = is_flushing_sync; + var prev_previous_batch = previous_batch; + previous_batch = null; is_flushing_sync = true; try { var result; if (fn) { - if (current_batch !== null && !current_batch.is_fork) { - current_batch.flush(); - } + flushSync(); // flush anything pending through the while loop below result = fn(); } @@ -1056,6 +1056,7 @@ export function flushSync(fn) { } } finally { is_flushing_sync = was_flushing_sync; + previous_batch = prev_previous_batch; } } @@ -1406,6 +1407,8 @@ export function fork(fn) { e.fork_timing(); } + flushSync(); + var batch = Batch.ensure(); batch.is_fork = true; batch_values = new Map(); @@ -1413,7 +1416,8 @@ export function fork(fn) { var committed = false; var settled = batch.settled(); - flushSync(fn); + fn(); + flushSync(); return { commit: async () => {