diff --git a/packages/svelte/src/compiler/phases/1-parse/state/tag.js b/packages/svelte/src/compiler/phases/1-parse/state/tag.js index ba091ef7ec..6c2162ebcc 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/tag.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/tag.js @@ -426,6 +426,7 @@ function open(parser) { body: create_fragment(), metadata: { can_hoist: false, + has_await: false, sites: new Set() } }); diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 92b89c588e..55f7b2d64a 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -303,6 +303,7 @@ export function analyze_module(source, options) { has_props_rune: false, options: /** @type {ValidatedCompileOptions} */ (options), fragment: null, + snippet: null, parent_element: null, reactive_statement: null }, @@ -531,7 +532,8 @@ export function analyze_component(root, source, options) { source, snippet_renderers: new Map(), snippets: new Set(), - async_deriveds: new Set() + async_deriveds: new Set(), + suspends: false }; state.adjust({ @@ -691,6 +693,7 @@ export function analyze_component(root, source, options) { options, ast_type: ast === instance.ast ? 'instance' : ast === template.ast ? 'template' : 'module', fragment: ast === template.ast ? ast : null, + snippet: null, parent_element: null, has_props_rune: false, component_slots: new Set(), @@ -757,6 +760,7 @@ export function analyze_component(root, source, options) { analysis, options, fragment: ast === template.ast ? ast : null, + snippet: null, parent_element: null, has_props_rune: false, ast_type: ast === instance.ast ? 'instance' : ast === template.ast ? 'template' : 'module', diff --git a/packages/svelte/src/compiler/phases/2-analyze/types.d.ts b/packages/svelte/src/compiler/phases/2-analyze/types.d.ts index 2d99a2e155..2573b05f21 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/types.d.ts +++ b/packages/svelte/src/compiler/phases/2-analyze/types.d.ts @@ -9,6 +9,7 @@ export interface AnalysisState { options: ValidatedCompileOptions; ast_type: 'instance' | 'template' | 'module'; fragment: AST.Fragment | null; + snippet: AST.SnippetBlock | null; /** * Tag name of the parent element. `null` if the parent is `svelte:element`, `#snippet`, a component or the root. * Parent doesn't necessarily mean direct path predecessor because there could be `#each`, `#if` etc in-between. diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js index b2f59b849b..68480f2c3b 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js @@ -23,6 +23,10 @@ export function AwaitExpression(node, context) { suspend = true; } + if (context.state.snippet) { + context.state.snippet.metadata.has_await = true; + } + // disallow top-level `await` or `await` in template expressions // unless a) in runes mode and b) opted into `experimental.async` if (suspend) { @@ -33,6 +37,8 @@ export function AwaitExpression(node, context) { if (!context.state.analysis.runes) { e.legacy_await_invalid(node); } + + context.state.analysis.suspends = true; } context.next(); diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/SnippetBlock.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/SnippetBlock.js index 7930c2b1a7..a30c384904 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/SnippetBlock.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/SnippetBlock.js @@ -23,7 +23,7 @@ export function SnippetBlock(node, context) { } } - context.next({ ...context.state, parent_element: null }); + context.next({ ...context.state, parent_element: null, snippet: node }); const can_hoist = context.path.length === 1 && diff --git a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js index 10c92242d4..df7ba38544 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js @@ -10,7 +10,6 @@ import { dev, filename } from '../../../state.js'; import { render_stylesheet } from '../css/index.js'; import { AssignmentExpression } from './visitors/AssignmentExpression.js'; import { AwaitBlock } from './visitors/AwaitBlock.js'; -import { AwaitExpression } from './visitors/AwaitExpression.js'; import { CallExpression } from './visitors/CallExpression.js'; import { ClassBody } from './visitors/ClassBody.js'; import { Component } from './visitors/Component.js'; @@ -45,7 +44,6 @@ import { SvelteBoundary } from './visitors/SvelteBoundary.js'; const global_visitors = { _: set_scope, AssignmentExpression, - AwaitExpression, CallExpression, ClassBody, ExpressionStatement, @@ -240,8 +238,19 @@ export function server_component(analysis, options) { } const component_block = b.block([ - .../** @type {Statement[]} */ (instance.body), - .../** @type {Statement[]} */ (template.body) + b.stmt( + b.call( + '$$payload.child', + b.arrow( + [], + b.block([ + .../** @type {Statement[]} */ (instance.body), + .../** @type {Statement[]} */ (template.body) + ]), + analysis.suspends + ) + ) + ) ]); // trick esrap into including comments diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/AwaitExpression.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/AwaitExpression.js deleted file mode 100644 index 9135892dbd..0000000000 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/AwaitExpression.js +++ /dev/null @@ -1,25 +0,0 @@ -/** @import { AwaitExpression } from 'estree' */ -/** @import { Context } from '../types.js' */ -import * as b from '../../../../utils/builders.js'; - -/** - * @param {AwaitExpression} node - * @param {Context} context - */ -export function AwaitExpression(node, context) { - // if `await` is inside a function, or inside `