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);