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 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 925abb9d9d46..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,7 +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; + 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; +} 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}