diff --git a/.changeset/fix-svelte-element-hydration.md b/.changeset/fix-svelte-element-hydration.md new file mode 100644 index 000000000000..916f6c5b43a9 --- /dev/null +++ b/.changeset/fix-svelte-element-hydration.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: handle svelte:element hydration within raw text elements diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js index 6df020d2d7ba..c3ed5a5d588f 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js @@ -88,9 +88,13 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio assign_nodes(element, element); if (render_fn) { + /** @type {Comment | null} */ + var comment = null; + if (hydrating && is_raw_text_element(next_tag)) { // prevent hydration glitches - element.append(document.createComment('')); + comment = document.createComment(''); + element.append(comment); } // If hydrating, use the existing ssr comment as the anchor so that the @@ -113,9 +117,15 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio // need to call `render_fn` in order to run actions etc. If the element // contains children, it's a user error (which is warned on elsewhere) // and the DOM will be silently discarded - render_fn(element, child_anchor); + try { + render_fn(element, child_anchor); + } finally { + if (comment !== null) { + comment.remove(); + } - set_animation_effect_override(null); + set_animation_effect_override(null); + } } // we do this after calling `render_fn` so that child effects don't override `nodes.end` diff --git a/packages/svelte/tests/hydration/samples/script/_expected.html b/packages/svelte/tests/hydration/samples/script/_expected.html index b3a4d922196b..3a19aa3b9b8d 100644 --- a/packages/svelte/tests/hydration/samples/script/_expected.html +++ b/packages/svelte/tests/hydration/samples/script/_expected.html @@ -1 +1 @@ - + diff --git a/packages/svelte/tests/runtime-runes/samples/svelte-element-style-hydration/_config.js b/packages/svelte/tests/runtime-runes/samples/svelte-element-style-hydration/_config.js new file mode 100644 index 000000000000..66d32136fccc --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/svelte-element-style-hydration/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +export default test({ + mode: ['hydrate'], + html: '
', + test({ assert, target }) { + const style = target.querySelector('style'); + assert.ok(style, 'style element should exist after hydration'); + if (style) { + for (const child of Array.from(style.childNodes)) { + assert.ok( + child.nodeType !== 8, // Node.COMMENT_NODE + 'style element should not contain comment nodes after hydration' + ); + } + } + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/svelte-element-style-hydration/main.svelte b/packages/svelte/tests/runtime-runes/samples/svelte-element-style-hydration/main.svelte new file mode 100644 index 000000000000..70c0ae987156 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/svelte-element-style-hydration/main.svelte @@ -0,0 +1,8 @@ + + +
+ {css} +