From be0b227afa777e39b1cd515b20890248ba642640 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Mon, 25 Nov 2024 14:38:02 +0000 Subject: [PATCH 1/2] fix: ensure last empty text node correctly hydrates --- .changeset/short-chicken-compare.md | 5 +++++ .../svelte/src/internal/client/dom/operations.js | 15 ++++++++++++--- .../hydration/samples/text-empty-2/_config.js | 3 +++ .../hydration/samples/text-empty-2/_expected.html | 1 + .../hydration/samples/text-empty-2/main.svelte | 7 +++++++ 5 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 .changeset/short-chicken-compare.md create mode 100644 packages/svelte/tests/hydration/samples/text-empty-2/_config.js create mode 100644 packages/svelte/tests/hydration/samples/text-empty-2/_expected.html create mode 100644 packages/svelte/tests/hydration/samples/text-empty-2/main.svelte diff --git a/.changeset/short-chicken-compare.md b/.changeset/short-chicken-compare.md new file mode 100644 index 000000000000..d0f6c22de4b7 --- /dev/null +++ b/.changeset/short-chicken-compare.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure last empty text node correctly hydrates diff --git a/packages/svelte/src/internal/client/dom/operations.js b/packages/svelte/src/internal/client/dom/operations.js index 6dfce9ebd320..0b34d4a1c73c 100644 --- a/packages/svelte/src/internal/client/dom/operations.js +++ b/packages/svelte/src/internal/client/dom/operations.js @@ -1,5 +1,5 @@ /** @import { TemplateNode } from '#client' */ -import { hydrate_node, hydrating, set_hydrate_node } from './hydration.js'; +import { hydrate_node, hydrating, next, set_hydrate_node } from './hydration.js'; import { DEV } from 'esm-env'; import { init_array_prototype_warnings } from '../dev/equality.js'; import { get_descriptor } from '../../shared/utils.js'; @@ -154,8 +154,10 @@ export function first_child(fragment, is_text) { */ export function sibling(node, count = 1, is_text = false) { let next_sibling = hydrating ? hydrate_node : node; + var last_sibling; while (count--) { + last_sibling = next_sibling; next_sibling = /** @type {TemplateNode} */ (get_next_sibling(next_sibling)); } @@ -163,13 +165,20 @@ export function sibling(node, count = 1, is_text = false) { return next_sibling; } - var type = next_sibling.nodeType; + var type = next_sibling?.nodeType; // if a sibling {expression} is empty during SSR, there might be no // text node to hydrate — we must therefore create one if (is_text && type !== 3) { var text = create_text(); - next_sibling?.before(text); + // If the next sibling is `null` and we're handling text then it's because + // the SSR content was empty for the text, so we need to generate a new text + // node and insert it after the last sibling + if (next_sibling === null) { + last_sibling?.after(text); + } else { + next_sibling.before(text); + } set_hydrate_node(text); return text; } diff --git a/packages/svelte/tests/hydration/samples/text-empty-2/_config.js b/packages/svelte/tests/hydration/samples/text-empty-2/_config.js new file mode 100644 index 000000000000..f47bee71df87 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/text-empty-2/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/packages/svelte/tests/hydration/samples/text-empty-2/_expected.html b/packages/svelte/tests/hydration/samples/text-empty-2/_expected.html new file mode 100644 index 000000000000..ff12f10bfb75 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/text-empty-2/_expected.html @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/hydration/samples/text-empty-2/main.svelte b/packages/svelte/tests/hydration/samples/text-empty-2/main.svelte new file mode 100644 index 000000000000..ae1ed05e3a84 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/text-empty-2/main.svelte @@ -0,0 +1,7 @@ + + + + {name}{remaining >= 2 ? ',' : ''} + From a6a7bfd28c2f3e6ae989922a9aecca1f188e51f1 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Mon, 25 Nov 2024 14:43:23 +0000 Subject: [PATCH 2/2] fix: ensure last empty text node correctly hydrates --- packages/svelte/src/internal/client/dom/operations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/src/internal/client/dom/operations.js b/packages/svelte/src/internal/client/dom/operations.js index 0b34d4a1c73c..627bf917eee1 100644 --- a/packages/svelte/src/internal/client/dom/operations.js +++ b/packages/svelte/src/internal/client/dom/operations.js @@ -1,5 +1,5 @@ /** @import { TemplateNode } from '#client' */ -import { hydrate_node, hydrating, next, set_hydrate_node } from './hydration.js'; +import { hydrate_node, hydrating, set_hydrate_node } from './hydration.js'; import { DEV } from 'esm-env'; import { init_array_prototype_warnings } from '../dev/equality.js'; import { get_descriptor } from '../../shared/utils.js';