From f7ce3f6a9985d4a79ceca4a09a7baca51000ce79 Mon Sep 17 00:00:00 2001 From: Jan Vogt Date: Wed, 25 Jun 2025 22:51:51 +0000 Subject: [PATCH 1/5] Add failing test for #16242 --- .../samples/whitespace-before-child/Nested.svelte | 1 + .../samples/whitespace-before-child/_override.html | 2 ++ .../hydration/samples/whitespace-before-child/main.svelte | 7 +++++++ 3 files changed, 10 insertions(+) create mode 100644 packages/svelte/tests/hydration/samples/whitespace-before-child/Nested.svelte create mode 100644 packages/svelte/tests/hydration/samples/whitespace-before-child/_override.html create mode 100644 packages/svelte/tests/hydration/samples/whitespace-before-child/main.svelte diff --git a/packages/svelte/tests/hydration/samples/whitespace-before-child/Nested.svelte b/packages/svelte/tests/hydration/samples/whitespace-before-child/Nested.svelte new file mode 100644 index 000000000000..c230e50ebc61 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/whitespace-before-child/Nested.svelte @@ -0,0 +1 @@ +

nested

diff --git a/packages/svelte/tests/hydration/samples/whitespace-before-child/_override.html b/packages/svelte/tests/hydration/samples/whitespace-before-child/_override.html new file mode 100644 index 000000000000..90ca4ef4b8c9 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/whitespace-before-child/_override.html @@ -0,0 +1,2 @@ + +

nested

\ No newline at end of file diff --git a/packages/svelte/tests/hydration/samples/whitespace-before-child/main.svelte b/packages/svelte/tests/hydration/samples/whitespace-before-child/main.svelte new file mode 100644 index 000000000000..0aa292515099 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/whitespace-before-child/main.svelte @@ -0,0 +1,7 @@ + +
+ +
From b4200fa5f1ce8972677625557bd83e6b42b5d49d Mon Sep 17 00:00:00 2001 From: Jan Vogt Date: Wed, 25 Jun 2025 22:52:59 +0000 Subject: [PATCH 2/5] Increase expectations for fix to #15819 one of the cases we CAN hydrate --- .../samples/cloudflare-mirage-borking-2/_config.js | 6 ------ .../samples/cloudflare-mirage-borking-2/_expected.html | 1 - .../samples/cloudflare-mirage-borking-2/main.svelte | 1 + 3 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_config.js delete mode 100644 packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_expected.html diff --git a/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_config.js b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_config.js deleted file mode 100644 index 56ba73b06408..000000000000 --- a/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_config.js +++ /dev/null @@ -1,6 +0,0 @@ -import { test } from '../../test'; - -// https://github.com/sveltejs/svelte/issues/15819 -export default test({ - expect_hydration_error: true -}); diff --git a/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_expected.html b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_expected.html deleted file mode 100644 index 5179fb04a5f7..000000000000 --- a/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_expected.html +++ /dev/null @@ -1 +0,0 @@ -

start

cond

diff --git a/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/main.svelte b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/main.svelte index bfb4f2cdb8cf..3f0097fb9ddd 100644 --- a/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/main.svelte +++ b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/main.svelte @@ -1,4 +1,5 @@ From a28a11edda049436675ffc7b5b1a9638c09d36f6 Mon Sep 17 00:00:00 2001 From: Jan Vogt Date: Wed, 25 Jun 2025 22:59:45 +0000 Subject: [PATCH 3/5] make hydration less whitespace sensitive this fixes #16242 and allows to sucessfully hydrate #15851 as well. --- .changeset/curvy-colts-occur.md | 5 +++++ packages/svelte/src/internal/client/dom/hydration.js | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 .changeset/curvy-colts-occur.md diff --git a/.changeset/curvy-colts-occur.md b/.changeset/curvy-colts-occur.md new file mode 100644 index 000000000000..3245e6638206 --- /dev/null +++ b/.changeset/curvy-colts-occur.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: make hydration less whitespace sensitive diff --git a/packages/svelte/src/internal/client/dom/hydration.js b/packages/svelte/src/internal/client/dom/hydration.js index 1f80b7922bc2..5ecdb1c236fb 100644 --- a/packages/svelte/src/internal/client/dom/hydration.js +++ b/packages/svelte/src/internal/client/dom/hydration.js @@ -1,6 +1,6 @@ /** @import { TemplateNode } from '#client' */ -import { COMMENT_NODE } from '#client/constants'; +import { COMMENT_NODE, TEXT_NODE } from '#client/constants'; import { HYDRATION_END, HYDRATION_ERROR, @@ -41,7 +41,13 @@ export function set_hydrate_node(node) { } export function hydrate_next() { - return set_hydrate_node(/** @type {TemplateNode} */ (get_next_sibling(hydrate_node))); + var node = set_hydrate_node(/** @type {TemplateNode} */(get_next_sibling(hydrate_node))); + while (hydrate_node.nodeType === TEXT_NODE && !hydrate_node.nodeValue?.trim()) { + var next_sibling = get_next_sibling(hydrate_node) + hydrate_node.parentElement?.removeChild(hydrate_node) + node = set_hydrate_node(/** @type {TemplateNode} */(next_sibling)) + } + return node } /** @param {TemplateNode} node */ From e9bd78259fb516554a6afab6cfa47b570fb98662 Mon Sep 17 00:00:00 2001 From: Jan Vogt Date: Thu, 26 Jun 2025 01:27:36 +0000 Subject: [PATCH 4/5] fix await blocks For some reason await blocks render html whitespace and their custom hydration error handling seems to depend on hydrating text nodes. --- .../src/internal/client/dom/blocks/await.js | 2 +- .../src/internal/client/dom/hydration.js | 20 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/blocks/await.js b/packages/svelte/src/internal/client/dom/blocks/await.js index 47df5fc9a5f8..2c3e3af4a798 100644 --- a/packages/svelte/src/internal/client/dom/blocks/await.js +++ b/packages/svelte/src/internal/client/dom/blocks/await.js @@ -36,7 +36,7 @@ const CATCH = 2; */ export function await_block(node, get_input, pending_fn, then_fn, catch_fn) { if (hydrating) { - hydrate_next(); + hydrate_next(true); } var anchor = node; diff --git a/packages/svelte/src/internal/client/dom/hydration.js b/packages/svelte/src/internal/client/dom/hydration.js index 5ecdb1c236fb..37492c80e298 100644 --- a/packages/svelte/src/internal/client/dom/hydration.js +++ b/packages/svelte/src/internal/client/dom/hydration.js @@ -40,9 +40,25 @@ export function set_hydrate_node(node) { return (hydrate_node = node); } -export function hydrate_next() { +/** + * Moove to the next node to be hydrated. Empty text nodes will be skipped, + * unless `allow_text` is set to true. + * + * Skipping whitespace helps to sucessful hydrate even if some middleware added + * arbitrary whitespace into the html. This was at least twice an issue: + * + * - https://github.com/sveltejs/svelte/issues/15819 + * - https://github.com/sveltejs/svelte/issues/16242 + * + * Removing empty text nodes should be finde, as required text nodes will be + * added on demand. Doing so is necessary because an empty text on the server + * side will result in a missing text nodes as well. + * + * @param {boolean} allow_text + */ +export function hydrate_next(allow_text = false) { var node = set_hydrate_node(/** @type {TemplateNode} */(get_next_sibling(hydrate_node))); - while (hydrate_node.nodeType === TEXT_NODE && !hydrate_node.nodeValue?.trim()) { + while (!allow_text && node.nodeType === TEXT_NODE && !node.nodeValue?.trim()) { var next_sibling = get_next_sibling(hydrate_node) hydrate_node.parentElement?.removeChild(hydrate_node) node = set_hydrate_node(/** @type {TemplateNode} */(next_sibling)) From 94c47847b49a7e6be99c0219fae9d4834cd0d59b Mon Sep 17 00:00:00 2001 From: Jan Vogt Date: Thu, 26 Jun 2025 07:39:01 +0000 Subject: [PATCH 5/5] prevent nix flake and direnv setup to leak --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index d50343766485..6d05d789a674 100644 --- a/.gitignore +++ b/.gitignore @@ -14,9 +14,13 @@ coverage # dotenv environment variables file .env .env.test +flake.nix +flake.lock +.envrc # build output .vercel +.direnv # OS-specific .DS_Store