diff --git a/.changeset/chilly-bats-build.md b/.changeset/chilly-bats-build.md new file mode 100644 index 0000000000..872e4c79c4 --- /dev/null +++ b/.changeset/chilly-bats-build.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: hydrate each blocks inside element correctly 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 62d07014ee..3588f2843a 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 @@ -99,7 +99,14 @@ export function process_children(nodes, initial, is_element, context) { if (is_static_element(node, context.state)) { skipped += 1; - } else if (node.type === 'EachBlock' && nodes.length === 1 && is_element) { + } else if ( + node.type === 'EachBlock' && + 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 + // TODO switch this around and instead optimize for elements with a single block child and not require extra comments (neither for async nor normally) + !(node.body.metadata.has_await || node.metadata.expression.has_await) + ) { node.metadata.is_controlled = true; } else { const id = flush_node(false, node.type === 'RegularElement' ? node.name : 'node'); diff --git a/packages/svelte/tests/runtime-runes/samples/async-each-sibling/_config.js b/packages/svelte/tests/runtime-runes/samples/async-each-sibling/_config.js new file mode 100644 index 0000000000..ff10a48f11 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-each-sibling/_config.js @@ -0,0 +1,16 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['async-server', 'hydrate', 'client'], + ssrHtml: `