diff --git a/.changeset/iife-await-const-blocker.md b/.changeset/iife-await-const-blocker.md new file mode 100644 index 0000000000..2b5c4f0323 --- /dev/null +++ b/.changeset/iife-await-const-blocker.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: propagate async `@const` blockers through closure references so template expressions like `{(() => host)()}` correctly wait for the awaited value diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js index 1f3c7b2256..51c84dd01c 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js @@ -52,7 +52,7 @@ export class Memoizer { * @param {ExpressionMetadata} metadata */ check_blockers(metadata) { - for (const binding of metadata.dependencies) { + for (const binding of metadata.references) { if (binding.blocker) { this.#blockers.add(binding.blocker); } diff --git a/packages/svelte/src/compiler/phases/nodes.js b/packages/svelte/src/compiler/phases/nodes.js index 2e54f333a8..48ebacb50b 100644 --- a/packages/svelte/src/compiler/phases/nodes.js +++ b/packages/svelte/src/compiler/phases/nodes.js @@ -102,8 +102,8 @@ export class ExpressionMetadata { if (!this.#blockers) { this.#blockers = new Set(); - for (const d of this.dependencies) { - if (d.blocker) this.#blockers.add(d.blocker); + for (const r of this.references) { + if (r.blocker) this.#blockers.add(r.blocker); } } diff --git a/packages/svelte/tests/runtime-runes/samples/async-each-const-await-iife/_config.js b/packages/svelte/tests/runtime-runes/samples/async-each-const-await-iife/_config.js new file mode 100644 index 0000000000..958c3023f1 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-each-const-await-iife/_config.js @@ -0,0 +1,14 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +// Tests that an IIFE referencing an `await` @const inside an {#each} block +// correctly registers the async dependency so the template waits for the +// resolved value instead of rendering with `undefined`. +export default test({ + mode: ['client', 'hydrate', 'async-server'], + ssrHtml: '
example.com
', + async test({ assert, target }) { + await tick(); + assert.htmlEqual(target.innerHTML, 'example.com
'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-each-const-await-iife/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-each-const-await-iife/main.svelte new file mode 100644 index 0000000000..e0ccbb7892 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-each-const-await-iife/main.svelte @@ -0,0 +1,10 @@ + + +{#each { length: 1 } as nothing} + {@const host = await get_host()} +{(() => host)()}
+{/each}