From 4656e6895dde764e99c01d9dd86379df2c881c8a Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Thu, 21 May 2026 20:26:09 +0200 Subject: [PATCH] fix: make unnecessary commit work less likely (#18263) While looking at https://github.com/sveltejs/svelte/issues/18221#issuecomment-4497918414 and trying to understand how the invariant can happen I noticed that we are not correctly filtering during commit. - we were not ignoring deriveds - we were not comparing the correct values (checking `source.v` instead of the saved value) and not checking if their "is a derived" state differs I'm not able to come up with a test where something fails without these (possibly because it's more about an optimization to do less reruns and not about correctness) fixes, but they do make sense. --- .changeset/tired-socks-brake.md | 5 +++++ .../src/internal/client/reactivity/batch.js | 19 ++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) create mode 100644 .changeset/tired-socks-brake.md diff --git a/.changeset/tired-socks-brake.md b/.changeset/tired-socks-brake.md new file mode 100644 index 0000000000..1d302ffa60 --- /dev/null +++ b/.changeset/tired-socks-brake.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: make unnecessary commit work less likely diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 2803ffc84c..4952001dd6 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -677,8 +677,10 @@ export class Batch { if (!batch.#started) continue; - // Re-run async/block effects that depend on distinct values changed in both batches - var others = [...batch.current.keys()].filter((s) => !this.current.has(s)); + // Re-run async/block effects that depend on distinct values changed in both batches (ignoring deriveds) + var others = [...batch.current.keys()].filter( + (s) => !(/** @type {[any, boolean]} */ (batch.current.get(s))[1]) && !this.current.has(s) + ); if (others.length === 0) { if (is_earlier) { @@ -718,11 +720,14 @@ export class Batch { } checked = new Map(); - var current_unequal = [...batch.current.keys()].filter((c) => - this.current.has(c) - ? /** @type {[any, boolean]} */ (this.current.get(c))[0] !== c.v - : true - ); + var current_unequal = [...batch.current] + .filter(([c, v1]) => { + const v2 = this.current.get(c); + if (!v2) return true; + // Either their values are different or one is a derived but not the other + return v2[0] !== v1[0] || v2[1] !== v1[1]; + }) + .map(([c]) => c); if (current_unequal.length > 0) { for (const effect of this.#new_effects) {