diff --git a/.changeset/fast-eyes-hear.md b/.changeset/fast-eyes-hear.md
new file mode 100644
index 000000000000..3fe951af15d4
--- /dev/null
+++ b/.changeset/fast-eyes-hear.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: ensure tree-shaken if blocks correctly hydrate
diff --git a/packages/svelte/src/internal/client/dom/blocks/boundary.js b/packages/svelte/src/internal/client/dom/blocks/boundary.js
index 7f4f000dceae..e6dab77be399 100644
--- a/packages/svelte/src/internal/client/dom/blocks/boundary.js
+++ b/packages/svelte/src/internal/client/dom/blocks/boundary.js
@@ -17,7 +17,7 @@ import {
hydrate_node,
hydrating,
next,
- remove_nodes,
+ traverse_nodes,
set_hydrate_node
} from '../hydration.js';
import { queue_micro_task } from '../task.js';
@@ -92,7 +92,7 @@ export function boundary(node, props, boundary_fn) {
} else if (hydrating) {
set_hydrate_node(hydrate_open);
next();
- set_hydrate_node(remove_nodes());
+ set_hydrate_node(traverse_nodes(true));
}
if (failed) {
diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js
index d62c575391bc..f7e25382f1d3 100644
--- a/packages/svelte/src/internal/client/dom/blocks/each.js
+++ b/packages/svelte/src/internal/client/dom/blocks/each.js
@@ -12,7 +12,7 @@ import {
hydrate_next,
hydrate_node,
hydrating,
- remove_nodes,
+ traverse_nodes,
set_hydrate_node,
set_hydrating
} from '../hydration.js';
@@ -160,7 +160,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
if (is_else !== (length === 0)) {
// hydration mismatch — remove the server-rendered DOM and start over
- anchor = remove_nodes();
+ anchor = traverse_nodes(true);
set_hydrate_node(anchor);
set_hydrating(false);
@@ -199,7 +199,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
// remove excess nodes
if (length > 0) {
- set_hydrate_node(remove_nodes());
+ set_hydrate_node(traverse_nodes(true));
}
}
diff --git a/packages/svelte/src/internal/client/dom/blocks/if.js b/packages/svelte/src/internal/client/dom/blocks/if.js
index 6a880f28bc98..ad0b15d78d80 100644
--- a/packages/svelte/src/internal/client/dom/blocks/if.js
+++ b/packages/svelte/src/internal/client/dom/blocks/if.js
@@ -4,9 +4,9 @@ import {
hydrate_next,
hydrate_node,
hydrating,
- remove_nodes,
set_hydrate_node,
- set_hydrating
+ set_hydrating,
+ traverse_nodes
} from '../hydration.js';
import { block, branch, pause_effect, resume_effect } from '../../reactivity/effects.js';
import { HYDRATION_START_ELSE } from '../../../../constants.js';
@@ -46,7 +46,7 @@ export function if_block(node, fn, elseif = false) {
/** @type {boolean | null} */ new_condition,
/** @type {null | ((anchor: Node) => void)} */ fn
) => {
- if (condition === (condition = new_condition)) return;
+ if (condition === (condition = new_condition) && !hydrating) return;
/** Whether or not there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */
let mismatch = false;
@@ -57,11 +57,14 @@ export function if_block(node, fn, elseif = false) {
if (condition === is_else) {
// Hydration mismatch: remove everything inside the anchor and start fresh.
// This could happen with `{#if browser}...{/if}`, for example
- anchor = remove_nodes();
+ anchor = traverse_nodes(true);
set_hydrate_node(anchor);
set_hydrating(false);
mismatch = true;
+ } else if (!fn) {
+ anchor = traverse_nodes();
+ set_hydrate_node(anchor);
}
}
diff --git a/packages/svelte/src/internal/client/dom/hydration.js b/packages/svelte/src/internal/client/dom/hydration.js
index 8523ff97d559..f921a82ffe00 100644
--- a/packages/svelte/src/internal/client/dom/hydration.js
+++ b/packages/svelte/src/internal/client/dom/hydration.js
@@ -81,8 +81,9 @@ export function next(count = 1) {
/**
* Removes all nodes starting at `hydrate_node` up until the next hydration end comment
+ * @param {boolean} [remove]
*/
-export function remove_nodes() {
+export function traverse_nodes(remove = false) {
var depth = 0;
var node = hydrate_node;
@@ -99,7 +100,9 @@ export function remove_nodes() {
}
var next = /** @type {TemplateNode} */ (get_next_sibling(node));
- node.remove();
+ if (remove) {
+ node.remove();
+ }
node = next;
}
}
diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts
index f6b5b21f8085..0d761919a8e0 100644
--- a/packages/svelte/types/index.d.ts
+++ b/packages/svelte/types/index.d.ts
@@ -1671,6 +1671,7 @@ declare module 'svelte/motion' {
*
*
* ```
+ * @since 5.8.0
*/
export class Spring {
constructor(value: T, options?: SpringOpts);