From 03f166117693c6daccb0bf46cf20464cbd3afae6 Mon Sep 17 00:00:00 2001 From: Matteo Battista Date: Wed, 30 Apr 2025 08:47:21 +0200 Subject: [PATCH 1/4] fix: update_branch with (anchor).data possible undefined --- packages/svelte/src/internal/client/dom/blocks/if.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/svelte/src/internal/client/dom/blocks/if.js b/packages/svelte/src/internal/client/dom/blocks/if.js index 925abb9d9d46..2f408c009c82 100644 --- a/packages/svelte/src/internal/client/dom/blocks/if.js +++ b/packages/svelte/src/internal/client/dom/blocks/if.js @@ -57,6 +57,7 @@ export function if_block(node, fn, [root_index, hydrate_index] = [0, 0]) { if (hydrating && hydrate_index !== -1) { if (root_index === 0) { const data = /** @type {Comment} */ (anchor).data; + if (!data) return; if (data === HYDRATION_START) { hydrate_index = 0; } else if (data === HYDRATION_START_ELSE) { From 84305cf2a911110a6f7d7fb519b223d6e87f3ba5 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 15 May 2025 11:46:07 -0400 Subject: [PATCH 2/4] error sooner --- .../svelte/src/internal/client/dom/blocks/each.js | 3 ++- .../svelte/src/internal/client/dom/blocks/if.js | 5 +++-- .../svelte/src/internal/client/dom/hydration.js | 13 +++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js index 92c953b541f8..2997664fa259 100644 --- a/packages/svelte/src/internal/client/dom/blocks/each.js +++ b/packages/svelte/src/internal/client/dom/blocks/each.js @@ -12,6 +12,7 @@ import { hydrate_next, hydrate_node, hydrating, + read_hydration_instruction, remove_nodes, set_hydrate_node, set_hydrating @@ -160,7 +161,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f let mismatch = false; if (hydrating) { - var is_else = /** @type {Comment} */ (anchor).data === HYDRATION_START_ELSE; + var is_else = read_hydration_instruction(anchor) === HYDRATION_START_ELSE; if (is_else !== (length === 0)) { // hydration mismatch — remove the server-rendered DOM and start over diff --git a/packages/svelte/src/internal/client/dom/blocks/if.js b/packages/svelte/src/internal/client/dom/blocks/if.js index 2f408c009c82..bf1098c3f465 100644 --- a/packages/svelte/src/internal/client/dom/blocks/if.js +++ b/packages/svelte/src/internal/client/dom/blocks/if.js @@ -4,6 +4,7 @@ import { hydrate_next, hydrate_node, hydrating, + read_hydration_instruction, remove_nodes, set_hydrate_node, set_hydrating @@ -56,8 +57,8 @@ export function if_block(node, fn, [root_index, hydrate_index] = [0, 0]) { if (hydrating && hydrate_index !== -1) { if (root_index === 0) { - const data = /** @type {Comment} */ (anchor).data; - if (!data) return; + const data = read_hydration_instruction(anchor); + if (data === HYDRATION_START) { hydrate_index = 0; } else if (data === HYDRATION_START_ELSE) { diff --git a/packages/svelte/src/internal/client/dom/hydration.js b/packages/svelte/src/internal/client/dom/hydration.js index 8523ff97d559..ab3256da82db 100644 --- a/packages/svelte/src/internal/client/dom/hydration.js +++ b/packages/svelte/src/internal/client/dom/hydration.js @@ -103,3 +103,16 @@ export function remove_nodes() { node = next; } } + +/** + * + * @param {TemplateNode} node + */ +export function read_hydration_instruction(node) { + if (!node || node.nodeType !== 8) { + w.hydration_mismatch(); + throw HYDRATION_ERROR; + } + + return /** @type {Comment} */ (node).data; +} From 941514506bea613de930e70bc38f18ced76310a6 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 15 May 2025 11:46:29 -0400 Subject: [PATCH 3/4] add tests --- .../samples/cloudflare-mirage-borking-2/_config.js | 6 ++++++ .../samples/cloudflare-mirage-borking-2/_expected.html | 1 + .../samples/cloudflare-mirage-borking-2/_override.html | 1 + .../samples/cloudflare-mirage-borking-2/main.svelte | 5 +++++ .../samples/cloudflare-mirage-borking/_config.js | 6 ++++++ .../samples/cloudflare-mirage-borking/_expected.html | 1 + .../samples/cloudflare-mirage-borking/_override.html | 1 + .../samples/cloudflare-mirage-borking/main.svelte | 9 +++++++++ 8 files changed, 30 insertions(+) create mode 100644 packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_config.js create mode 100644 packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_expected.html create mode 100644 packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_override.html create mode 100644 packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/main.svelte create mode 100644 packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/_config.js create mode 100644 packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/_expected.html create mode 100644 packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/_override.html create mode 100644 packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/main.svelte 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 new file mode 100644 index 000000000000..56ba73b06408 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_config.js @@ -0,0 +1,6 @@ +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 new file mode 100644 index 000000000000..5179fb04a5f7 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_expected.html @@ -0,0 +1 @@ +

start

cond

diff --git a/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_override.html b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_override.html new file mode 100644 index 000000000000..2a1c32328897 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/_override.html @@ -0,0 +1 @@ +

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 new file mode 100644 index 000000000000..bfb4f2cdb8cf --- /dev/null +++ b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking-2/main.svelte @@ -0,0 +1,5 @@ + + +

start

{#if cond}

cond

{/if} diff --git a/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/_config.js b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/_config.js new file mode 100644 index 000000000000..56ba73b06408 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/_config.js @@ -0,0 +1,6 @@ +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/_expected.html b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/_expected.html new file mode 100644 index 000000000000..f6c03b87c1c2 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/_expected.html @@ -0,0 +1 @@ +

start

pre123 mid diff --git a/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/_override.html b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/_override.html new file mode 100644 index 000000000000..c84efbb00bd2 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/_override.html @@ -0,0 +1 @@ +

start

pre123 mid diff --git a/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/main.svelte b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/main.svelte new file mode 100644 index 000000000000..2c9a94686eb3 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/cloudflare-mirage-borking/main.svelte @@ -0,0 +1,9 @@ + + +

start

+pre123 +{#if cond} +mid +{/if} From 2caf059768256adf8543bd6ba0155a3ff763c831 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 15 May 2025 11:50:29 -0400 Subject: [PATCH 4/4] changeset --- .changeset/silly-apples-remain.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/silly-apples-remain.md diff --git a/.changeset/silly-apples-remain.md b/.changeset/silly-apples-remain.md new file mode 100644 index 000000000000..10d43db55087 --- /dev/null +++ b/.changeset/silly-apples-remain.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: handle more hydration mismatches