From 7c9ff8fc697a0723129d781e5bf116cf38e016f6 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 12 Mar 2026 09:28:43 -0400 Subject: [PATCH] fix: resolve boundary in correct batch when hydrating (#17914) Fixes #17907. When hydrating, we were resolving the boundary in the hydration batch rather than the batch created inside the `queue_micro_task` inside `#hydrate_pending_content`. This meant that effects got scheduled inside a batch that was already resolved. ### Before submitting the PR, please make sure you do the following - [x] 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. - [x] 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/stale-loops-love.md | 5 +++++ .../svelte/src/internal/client/dom/blocks/boundary.js | 8 ++------ .../samples/effect-in-pending-boundary/Child.svelte | 5 +++++ .../samples/effect-in-pending-boundary/_config.js | 7 +++++++ .../samples/effect-in-pending-boundary/main.svelte | 11 +++++++++++ 5 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 .changeset/stale-loops-love.md create mode 100644 packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/Child.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/main.svelte diff --git a/.changeset/stale-loops-love.md b/.changeset/stale-loops-love.md new file mode 100644 index 0000000000..d36392cca3 --- /dev/null +++ b/.changeset/stale-loops-love.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: resolve boundary in correct batch when hydrating diff --git a/packages/svelte/src/internal/client/dom/blocks/boundary.js b/packages/svelte/src/internal/client/dom/blocks/boundary.js index b38a3131ca..8046f1e222 100644 --- a/packages/svelte/src/internal/client/dom/blocks/boundary.js +++ b/packages/svelte/src/internal/client/dom/blocks/boundary.js @@ -218,8 +218,6 @@ export class Boundary { this.is_pending = true; this.#pending_effect = branch(() => pending(this.#anchor)); - var batch = /** @type {Batch} */ (current_batch); - queue_micro_task(() => { var fragment = (this.#offscreen_fragment = document.createDocumentFragment()); var anchor = create_text(); @@ -238,14 +236,12 @@ export class Boundary { this.#pending_effect = null; }); - this.#resolve(batch); + this.#resolve(/** @type {Batch} */ (current_batch)); } }); } #render() { - var batch = /** @type {Batch} */ (current_batch); - try { this.is_pending = this.has_pending_snippet(); this.#pending_count = 0; @@ -262,7 +258,7 @@ export class Boundary { const pending = /** @type {(anchor: Node) => void} */ (this.#props.pending); this.#pending_effect = branch(() => pending(this.#anchor)); } else { - this.#resolve(batch); + this.#resolve(/** @type {Batch} */ (current_batch)); } } catch (error) { this.error(error); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/Child.svelte b/packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/Child.svelte new file mode 100644 index 0000000000..0f18e43e56 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/Child.svelte @@ -0,0 +1,5 @@ + diff --git a/packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/_config.js new file mode 100644 index 0000000000..21575231ee --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, logs }) { + assert.deepEqual(logs, ['hello from child']); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/main.svelte new file mode 100644 index 0000000000..c4c0ef23ab --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/effect-in-pending-boundary/main.svelte @@ -0,0 +1,11 @@ + + + + + + {#snippet pending()} +

Loading...

+ {/snippet} +