diff --git a/.changeset/four-beers-like.md b/.changeset/four-beers-like.md new file mode 100644 index 0000000000..967d76af66 --- /dev/null +++ b/.changeset/four-beers-like.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: prevent hydration error on async `{@html ...}` diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js index bd3e708662..f77af74f7e 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/fragment.js @@ -101,7 +101,7 @@ export function process_children(nodes, initial, is_element, context) { if (is_static_element(node)) { skipped += 1; } else if ( - node.type === 'EachBlock' && + (node.type === 'EachBlock' || node.type === 'HtmlTag') && nodes.length === 1 && is_element && // In case it's wrapped in async the async logic will want to skip sibling nodes up until the end, hence we cannot make this controlled @@ -109,8 +109,6 @@ export function process_children(nodes, initial, is_element, context) { !node.metadata.expression.is_async() ) { node.metadata.is_controlled = true; - } else if (node.type === 'HtmlTag' && nodes.length === 1 && is_element) { - node.metadata.is_controlled = true; } else { const id = flush_node( false, diff --git a/packages/svelte/tests/runtime-runes/samples/async-hydrate-html-tag/_config.js b/packages/svelte/tests/runtime-runes/samples/async-hydrate-html-tag/_config.js new file mode 100644 index 0000000000..cb73ab1833 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-hydrate-html-tag/_config.js @@ -0,0 +1,10 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['hydrate'], + async test({ assert, target }) { + await tick(); + assert.htmlEqual(target.innerHTML, `
first test