From 923d5f87b88f6c9e1c598ede57b555193c663fde Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 6 Aug 2024 21:11:52 +0100 Subject: [PATCH 01/14] fix: provide more hydration mismatch coverage --- .changeset/stupid-rivers-stare.md | 5 +++++ packages/svelte/src/internal/client/dom/hydration.js | 6 ++++++ 2 files changed, 11 insertions(+) create mode 100644 .changeset/stupid-rivers-stare.md diff --git a/.changeset/stupid-rivers-stare.md b/.changeset/stupid-rivers-stare.md new file mode 100644 index 000000000000..d1d730cd2173 --- /dev/null +++ b/.changeset/stupid-rivers-stare.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: provide more hydration mismatch coverage diff --git a/packages/svelte/src/internal/client/dom/hydration.js b/packages/svelte/src/internal/client/dom/hydration.js index 5f0880a67654..f9bd3df84d70 100644 --- a/packages/svelte/src/internal/client/dom/hydration.js +++ b/packages/svelte/src/internal/client/dom/hydration.js @@ -44,6 +44,12 @@ export function hydrate_next() { /** @param {TemplateNode} node */ export function reset(node) { if (hydrating) { + // If we are resetting back to a parent, then we should be at the end of the current parent + // and thus have no more siblings to hydrate (except if we're inside a template). + if (hydrate_node?.nextSibling !== null && hydrate_node.nodeName !== 'TEMPLATE') { + w.hydration_mismatch(); + throw HYDRATION_ERROR; + } hydrate_node = node; } } From f15c88e3e30de09696a8492a025cba9586cbaf86 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Tue, 6 Aug 2024 21:16:00 +0100 Subject: [PATCH 02/14] tweak --- packages/svelte/src/internal/client/dom/hydration.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/internal/client/dom/hydration.js b/packages/svelte/src/internal/client/dom/hydration.js index f9bd3df84d70..291ccd7e92e6 100644 --- a/packages/svelte/src/internal/client/dom/hydration.js +++ b/packages/svelte/src/internal/client/dom/hydration.js @@ -46,7 +46,11 @@ export function reset(node) { if (hydrating) { // If we are resetting back to a parent, then we should be at the end of the current parent // and thus have no more siblings to hydrate (except if we're inside a template). - if (hydrate_node?.nextSibling !== null && hydrate_node.nodeName !== 'TEMPLATE') { + if ( + hydrate_node !== null && + hydrate_node.nextSibling !== null && + hydrate_node.nodeName !== 'TEMPLATE' + ) { w.hydration_mismatch(); throw HYDRATION_ERROR; } From 4c277ecaa0dcb6ecb1f7d7c8ec1cb3e0ac2a9862 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 10 Aug 2024 09:16:13 -0400 Subject: [PATCH 03/14] add test for safari borking stuff --- .../hydration/samples/safari-borking/_expected.html | 1 + .../hydration/samples/safari-borking/_override.html | 1 + .../tests/hydration/samples/safari-borking/main.svelte | 5 +++++ .../samples/surrounding-whitespace/_expected.html | 2 ++ packages/svelte/tests/hydration/test.ts | 9 ++++----- playgrounds/demo/index.html | 5 ++++- 6 files changed, 17 insertions(+), 6 deletions(-) create mode 100644 packages/svelte/tests/hydration/samples/safari-borking/_expected.html create mode 100644 packages/svelte/tests/hydration/samples/safari-borking/_override.html create mode 100644 packages/svelte/tests/hydration/samples/safari-borking/main.svelte create mode 100644 packages/svelte/tests/hydration/samples/surrounding-whitespace/_expected.html diff --git a/packages/svelte/tests/hydration/samples/safari-borking/_expected.html b/packages/svelte/tests/hydration/samples/safari-borking/_expected.html new file mode 100644 index 000000000000..b90bfa5aedc3 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/safari-borking/_expected.html @@ -0,0 +1 @@ +

call +636-555-3226 now

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

call +636-555-3226 now

diff --git a/packages/svelte/tests/hydration/samples/safari-borking/main.svelte b/packages/svelte/tests/hydration/samples/safari-borking/main.svelte new file mode 100644 index 000000000000..1385fbb2a462 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/safari-borking/main.svelte @@ -0,0 +1,5 @@ + + +

{message}

diff --git a/packages/svelte/tests/hydration/samples/surrounding-whitespace/_expected.html b/packages/svelte/tests/hydration/samples/surrounding-whitespace/_expected.html new file mode 100644 index 000000000000..e728b682d0cd --- /dev/null +++ b/packages/svelte/tests/hydration/samples/surrounding-whitespace/_expected.html @@ -0,0 +1,2 @@ + + hello diff --git a/packages/svelte/tests/hydration/test.ts b/packages/svelte/tests/hydration/test.ts index d592a65de3d8..eec4c40240f5 100644 --- a/packages/svelte/tests/hydration/test.ts +++ b/packages/svelte/tests/hydration/test.ts @@ -113,11 +113,10 @@ const { test, run } = suite(async (config, cwd) => { throw new Error(`Unexpected errors: ${errors.join('\n')}`); } - if (!override) { - const expected = read(`${cwd}/_expected.html`) ?? rendered.html; - flushSync(); - assert.equal(target.innerHTML.trim(), expected.trim()); - } + flushSync(); + + const expected = read(`${cwd}/_expected.html`) ?? rendered.html; + assert.equal(target.innerHTML.trim(), expected.trim()); if (rendered.head) { const expected = read(`${cwd}/_expected_head.html`) ?? rendered.head; diff --git a/playgrounds/demo/index.html b/playgrounds/demo/index.html index fae74ccb1e18..be5e466a013e 100644 --- a/playgrounds/demo/index.html +++ b/playgrounds/demo/index.html @@ -8,7 +8,10 @@ -
+ +
+

call +636-555-3226 now

+
+ +{message} diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js b/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js new file mode 100644 index 000000000000..cf22ff2c85dc --- /dev/null +++ b/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + expect_hydration_error: true +}); diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/_expected.html b/packages/svelte/tests/hydration/samples/safari-borking-2/_expected.html new file mode 100644 index 000000000000..09679aa1417b --- /dev/null +++ b/packages/svelte/tests/hydration/samples/safari-borking-2/_expected.html @@ -0,0 +1 @@ +
call +636-555-3226 now
diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html b/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html new file mode 100644 index 000000000000..e7867d6769ef --- /dev/null +++ b/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html @@ -0,0 +1 @@ +
call +636-555-3226 now
diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte b/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte new file mode 100644 index 000000000000..6750b93a2c5e --- /dev/null +++ b/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte @@ -0,0 +1,5 @@ + + + From 548ac5ad6d76f88e2e11ead57b37cb2c2c1df7df Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 10 Aug 2024 10:40:13 -0400 Subject: [PATCH 07/14] oops --- packages/svelte/tests/hydration/test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/tests/hydration/test.ts b/packages/svelte/tests/hydration/test.ts index 5e7fb32ab230..7247778d0ffa 100644 --- a/packages/svelte/tests/hydration/test.ts +++ b/packages/svelte/tests/hydration/test.ts @@ -115,7 +115,7 @@ const { test, run } = suite(async (config, cwd) => { flushSync(); - const normalize = (string: string) => string.trim().replace(/\n\r/g, '\n'); + const normalize = (string: string) => string.trim().replace(/\r\n/g, '\n'); const expected = read(`${cwd}/_expected.html`) ?? rendered.html; assert.equal(normalize(target.innerHTML), normalize(expected)); From 0cbebb61c7f531259e1176f33e9011fb7d849643 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 10 Aug 2024 10:46:30 -0400 Subject: [PATCH 08/14] revert playground changes --- playgrounds/demo/index.html | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/playgrounds/demo/index.html b/playgrounds/demo/index.html index be5e466a013e..fae74ccb1e18 100644 --- a/playgrounds/demo/index.html +++ b/playgrounds/demo/index.html @@ -8,10 +8,7 @@ - -
-

call +636-555-3226 now

-
+
- -{message} diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js b/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js deleted file mode 100644 index cf22ff2c85dc..000000000000 --- a/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js +++ /dev/null @@ -1,5 +0,0 @@ -import { test } from '../../test'; - -export default test({ - expect_hydration_error: true -}); diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/_expected.html b/packages/svelte/tests/hydration/samples/safari-borking-2/_expected.html deleted file mode 100644 index 09679aa1417b..000000000000 --- a/packages/svelte/tests/hydration/samples/safari-borking-2/_expected.html +++ /dev/null @@ -1 +0,0 @@ -
call +636-555-3226 now
diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html b/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html deleted file mode 100644 index e7867d6769ef..000000000000 --- a/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html +++ /dev/null @@ -1 +0,0 @@ -
call +636-555-3226 now
diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte b/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte deleted file mode 100644 index 6750b93a2c5e..000000000000 --- a/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - - From 47f20b180acddf12f457978ce0e759f3eabae6b2 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 10 Aug 2024 11:59:03 -0400 Subject: [PATCH 12/14] update comment to no longer mention templates --- packages/svelte/src/internal/client/dom/hydration.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/svelte/src/internal/client/dom/hydration.js b/packages/svelte/src/internal/client/dom/hydration.js index b2cf0c63c202..82ad0df6133c 100644 --- a/packages/svelte/src/internal/client/dom/hydration.js +++ b/packages/svelte/src/internal/client/dom/hydration.js @@ -46,8 +46,7 @@ export function hydrate_next() { export function reset(node) { if (!hydrating) return; - // If we are resetting back to a parent, then we should be at the end of the current parent - // and thus have no more siblings to hydrate (except if we're inside a template). + // If the node has remaining siblings, something has gone wrong if (hydrate_node.nextSibling !== null) { w.hydration_mismatch(); throw HYDRATION_ERROR; From 525bc2859ddfda2e0fe4ca3a6700644c2c46a272 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 10 Aug 2024 12:23:26 -0400 Subject: [PATCH 13/14] failing test --- .../tests/hydration/samples/safari-borking-2/Child.svelte | 6 ++++++ .../tests/hydration/samples/safari-borking-2/_config.js | 5 +++++ .../tests/hydration/samples/safari-borking-2/_override.html | 1 + .../tests/hydration/samples/safari-borking-2/main.svelte | 6 ++++++ playgrounds/demo/ssr-dev.js | 4 +++- 5 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 packages/svelte/tests/hydration/samples/safari-borking-2/Child.svelte create mode 100644 packages/svelte/tests/hydration/samples/safari-borking-2/_config.js create mode 100644 packages/svelte/tests/hydration/samples/safari-borking-2/_override.html create mode 100644 packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/Child.svelte b/packages/svelte/tests/hydration/samples/safari-borking-2/Child.svelte new file mode 100644 index 000000000000..a62bd4ec9044 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/safari-borking-2/Child.svelte @@ -0,0 +1,6 @@ + + +
+{message} diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js b/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js new file mode 100644 index 000000000000..cf22ff2c85dc --- /dev/null +++ b/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + expect_hydration_error: true +}); diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html b/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html new file mode 100644 index 000000000000..17ec01970aea --- /dev/null +++ b/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html @@ -0,0 +1 @@ +
call +636-555-3226 now

42

diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte b/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte new file mode 100644 index 000000000000..daa25067ec76 --- /dev/null +++ b/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte @@ -0,0 +1,6 @@ + + + +

{40 + 2}

diff --git a/playgrounds/demo/ssr-dev.js b/playgrounds/demo/ssr-dev.js index 617b49e652a4..65390b70cac5 100644 --- a/playgrounds/demo/ssr-dev.js +++ b/playgrounds/demo/ssr-dev.js @@ -27,7 +27,9 @@ polka() const html = transformed_template .replace(``, head) - .replace(``, body); + .replace(``, body) + // check that Safari doesn't break hydration + .replaceAll('+636-555-3226', '+636-555-3226'); res.writeHead(200, { 'Content-Type': 'text/html' }).end(html); }) From c30f53de6b3df484de4fb58c787e935fa676041a Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 10 Aug 2024 12:30:26 -0400 Subject: [PATCH 14/14] delete test for now --- .../tests/hydration/samples/safari-borking-2/Child.svelte | 6 ------ .../tests/hydration/samples/safari-borking-2/_config.js | 5 ----- .../tests/hydration/samples/safari-borking-2/_override.html | 1 - .../tests/hydration/samples/safari-borking-2/main.svelte | 6 ------ 4 files changed, 18 deletions(-) delete mode 100644 packages/svelte/tests/hydration/samples/safari-borking-2/Child.svelte delete mode 100644 packages/svelte/tests/hydration/samples/safari-borking-2/_config.js delete mode 100644 packages/svelte/tests/hydration/samples/safari-borking-2/_override.html delete mode 100644 packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/Child.svelte b/packages/svelte/tests/hydration/samples/safari-borking-2/Child.svelte deleted file mode 100644 index a62bd4ec9044..000000000000 --- a/packages/svelte/tests/hydration/samples/safari-borking-2/Child.svelte +++ /dev/null @@ -1,6 +0,0 @@ - - -
-{message} diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js b/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js deleted file mode 100644 index cf22ff2c85dc..000000000000 --- a/packages/svelte/tests/hydration/samples/safari-borking-2/_config.js +++ /dev/null @@ -1,5 +0,0 @@ -import { test } from '../../test'; - -export default test({ - expect_hydration_error: true -}); diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html b/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html deleted file mode 100644 index 17ec01970aea..000000000000 --- a/packages/svelte/tests/hydration/samples/safari-borking-2/_override.html +++ /dev/null @@ -1 +0,0 @@ -
call +636-555-3226 now

42

diff --git a/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte b/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte deleted file mode 100644 index daa25067ec76..000000000000 --- a/packages/svelte/tests/hydration/samples/safari-borking-2/main.svelte +++ /dev/null @@ -1,6 +0,0 @@ - - - -

{40 + 2}