From b7510b016d8d9a391cce7245299ef338499fb91d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 25 Oct 2025 21:49:57 -0400 Subject: [PATCH] WIP --- .../3-transform/server/visitors/IfBlock.js | 16 +++++++--- .../server/visitors/shared/utils.js | 10 +++++-- .../svelte/src/internal/server/renderer.js | 29 +++++++++++++++++-- .../async-if-after-await-in-script/_config.js | 16 ++++++++++ .../main.svelte | 10 +++++++ 5 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 packages/svelte/tests/runtime-runes/samples/async-if-after-await-in-script/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/async-if-after-await-in-script/main.svelte diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/IfBlock.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/IfBlock.js index a869a8edf1..ca614a93e2 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/IfBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/IfBlock.js @@ -23,12 +23,20 @@ export function IfBlock(node, context) { /** @type {Statement} */ let statement = b.if(test, consequent, alternate); - if ( + const is_async = node.metadata.expression.is_async(); + + const has_await = node.metadata.expression.has_await || + // TODO get rid of this stuff node.consequent.metadata.has_await || - node.alternate?.metadata.has_await - ) { - statement = create_async_block(b.block([statement])); + node.alternate?.metadata.has_await; + + if (is_async || has_await) { + statement = create_async_block( + b.block([statement]), + node.metadata.expression.blockers(), + !!has_await + ); } context.state.template.push(statement, block_close); diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/utils.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/utils.js index 09a854670c..1e4ac69608 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/shared/utils.js @@ -1,4 +1,4 @@ -/** @import { Expression, Identifier, Node, Statement, BlockStatement } from 'estree' */ +/** @import { Expression, Identifier, Node, Statement, BlockStatement, ArrayExpression } from 'estree' */ /** @import { AST } from '#compiler' */ /** @import { ComponentContext, ServerTransformState } from '../../types.js' */ @@ -275,9 +275,13 @@ export function create_child_block(body, async) { /** * Creates a `$$renderer.async(...)` expression statement * @param {BlockStatement | Expression} body + * @param {ArrayExpression} blockers + * @param {boolean} has_await */ -export function create_async_block(body) { - return b.stmt(b.call('$$renderer.async', b.arrow([b.id('$$renderer')], body, true))); +export function create_async_block(body, blockers, has_await) { + return b.stmt( + b.call('$$renderer.async', blockers, b.arrow([b.id('$$renderer')], body, has_await)) + ); } /** diff --git a/packages/svelte/src/internal/server/renderer.js b/packages/svelte/src/internal/server/renderer.js index fb1af6ffbb..d20792c91f 100644 --- a/packages/svelte/src/internal/server/renderer.js +++ b/packages/svelte/src/internal/server/renderer.js @@ -100,18 +100,41 @@ export class Renderer { } /** + * @param {Array>} blockers * @param {(renderer: Renderer) => void} fn */ - async(fn) { + async(blockers, fn) { this.#out.push(BLOCK_OPEN); - this.child(fn); + this.child( + blockers.length > 0 ? (renderer) => Promise.all(blockers).then(() => fn(renderer)) : fn + ); this.#out.push(BLOCK_CLOSE); } /** * @param {Array<() => void>} thunks */ - run(thunks) {} + run(thunks) { + const context = ssr_context; + + let promise = Promise.resolve(thunks[0]()); + const promises = [promise]; + + for (const fn of thunks.slice(1)) { + promise = promise.then(() => { + const previous_ssr_context = ssr_context; + set_ssr_context(context); + + try { + return fn(); + } finally { + set_ssr_context(previous_ssr_context); + } + }); + } + + return promises; + } /** * Create a child renderer. The child renderer inherits the state from the parent, diff --git a/packages/svelte/tests/runtime-runes/samples/async-if-after-await-in-script/_config.js b/packages/svelte/tests/runtime-runes/samples/async-if-after-await-in-script/_config.js new file mode 100644 index 0000000000..2b8ab6e894 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-if-after-await-in-script/_config.js @@ -0,0 +1,16 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + ssrHtml: '

yep

', + + async test({ assert, target, variant }) { + if (variant === 'dom') { + await tick(); + } + + assert.htmlEqual(target.innerHTML, '

yep

'); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/async-if-after-await-in-script/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-if-after-await-in-script/main.svelte new file mode 100644 index 0000000000..66dc7c718c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/async-if-after-await-in-script/main.svelte @@ -0,0 +1,10 @@ + + +{#if condition} +

yep

+{:else} +

nope

+{/if}