From 18479217a736e51fa570b13cf1a4ae035c84e2ff Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 2 Apr 2026 21:52:08 -0400 Subject: [PATCH] create new active_batch concept --- .../svelte/src/internal/client/reactivity/batch.js | 14 ++++++++++++++ .../src/internal/client/reactivity/deriveds.js | 9 ++++----- packages/svelte/src/internal/client/runtime.js | 3 ++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 4c6efad89c..47e55bb2fc 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -53,6 +53,15 @@ const batches = new Set(); /** @type {Batch | null} */ export let current_batch = null; +/** + * The batch that is currently applied. May not be the same as `current_batch`, since we + * null that out when flushing effects in case they set state, resulting in a new + * batch being created. Effects always run inside an active_batch. + * TODO most occurrences of `current_batch` should be this + * @type {Batch | null} + **/ +export let active_batch = null; + /** * This is needed to avoid overwriting inputs * @type {Batch | null} @@ -353,6 +362,8 @@ export class Batch { batch.#roots.push(...this.#roots.filter((r) => !batch.#roots.includes(r))); } + active_batch = null; + if (next_batch !== null) { batches.add(next_batch); @@ -507,6 +518,7 @@ export class Batch { is_processing = false; current_batch = null; + active_batch = null; batch_values = batch_cvs = batch_wvs = null; old_values.clear(); @@ -738,6 +750,8 @@ export class Batch { return; } + active_batch = this; + // if there are multiple batches, we are 'time travelling' — // we need to override values with the ones in this batch... batch_values = new Map(this.current); diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js index d574f8100a..dc88ef70eb 100644 --- a/packages/svelte/src/internal/client/reactivity/deriveds.js +++ b/packages/svelte/src/internal/client/reactivity/deriveds.js @@ -31,7 +31,7 @@ import { get_error } from '../../shared/dev.js'; import { async_mode_flag, tracing_mode_flag } from '../../flags/index.js'; import { component_context } from '../context.js'; import { UNINITIALIZED } from '../../../constants.js'; -import { batch_wvs, current_batch, get_wv, set_cv } from './batch.js'; +import { current_batch, get_wv, active_batch, set_cv } from './batch.js'; import { increment_pending, unset_context } from './async.js'; import { deferred, noop } from '../../shared/utils.js'; @@ -393,10 +393,9 @@ export function update_derived(derived) { set_cv(derived, cv); if (!derived.equals(value)) { - batch_wvs?.set(derived, write_version); - - if (current_batch !== null) { - current_batch.capture_derived(derived, value); + if (active_batch !== null) { + active_batch.capture_derived(derived, value); + active_batch.wvs.set(derived, write_version); } else { derived.v = value; derived.wv = write_version; diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 3833193914..e278976975 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -52,6 +52,7 @@ import { current_batch, flushSync, get_cv, + active_batch, schedule_effect, set_cv } from './reactivity/batch.js'; @@ -188,7 +189,7 @@ export function is_dirty(reaction) { } } - var wv = batch_wvs?.get(dependency) ?? dependency.wv; + var wv = active_batch?.wvs.get(dependency) ?? dependency.wv; if (wv > cv) { return true;