From 9ffc13d7c3a9360591e1ad45209b10024e3a8333 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 8 May 2026 12:55:29 -0400 Subject: [PATCH] fix: remove `source.updated` stack traces after `flush` (#18196) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed that we're not actually doing anything with `source_stacks` — we shadow the module-level declaration in `flush`, which means we just keep appending to it and then clearing a different (and empty) set. As a result, any source that ever gets an `updated` property never gets rid of it. This probably causes a memory leak? Anyway, this fixes it. ### Before submitting the PR, please make sure you do the following - [ ] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs - [x] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`. - [x] This message body should clearly illustrate what problems it solves. - [ ] Ideally, include a test that fails without this PR but passes with it. - [x] If this PR changes code within `packages/svelte/src`, add a changeset (`npx changeset`). ### Tests and linting - [x] Run the tests with `pnpm test` and lint the project with `pnpm lint` --- .changeset/red-crabs-ring.md | 5 ++++ .../src/internal/client/reactivity/batch.js | 26 ++++++++++++------- 2 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 .changeset/red-crabs-ring.md diff --git a/.changeset/red-crabs-ring.md b/.changeset/red-crabs-ring.md new file mode 100644 index 0000000000..82b53c5464 --- /dev/null +++ b/.changeset/red-crabs-ring.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: reset `source.updated` stack traces after `flush` diff --git a/packages/svelte/src/internal/client/reactivity/batch.js b/packages/svelte/src/internal/client/reactivity/batch.js index 418e2a8f1a..dfa53788f3 100644 --- a/packages/svelte/src/internal/client/reactivity/batch.js +++ b/packages/svelte/src/internal/client/reactivity/batch.js @@ -85,7 +85,9 @@ export let collected_effects = null; export let legacy_updates = null; var flush_count = 0; -var source_stacks = DEV ? new Set() : null; + +/** @type {Set} */ +var source_stacks = new Set(); let uid = 1; @@ -273,6 +275,14 @@ export class Batch { infinite_loop_guard(); } + if (DEV) { + // track all the values that were updated during this flush, + // so that they can be reset afterwards + for (const value of this.current.keys()) { + source_stacks.add(value); + } + } + // we only reschedule previously-deferred effects if we expect // to be able to run them after processing the batch if (!this.#is_deferred()) { @@ -377,12 +387,6 @@ export class Batch { } if (next_batch !== null) { - if (DEV) { - for (const source of this.current.keys()) { - /** @type {Set} */ (source_stacks).add(source); - } - } - next_batch.#process(); } } @@ -481,9 +485,11 @@ export class Batch { } flush() { - var source_stacks = DEV ? new Set() : null; - try { + if (DEV) { + source_stacks.clear(); + } + is_processing = true; current_batch = this; @@ -501,7 +507,7 @@ export class Batch { old_values.clear(); if (DEV) { - for (const source of /** @type {Set} */ (source_stacks)) { + for (const source of source_stacks) { source.updated = null; } }