From e2bc4d937fd9283d2267fe7fe5b078f4fa4c40d5 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 15 Jan 2025 17:27:08 -0500 Subject: [PATCH] top-level await --- .../src/compiler/phases/2-analyze/index.js | 3 ++- .../2-analyze/visitors/AwaitExpression.js | 8 ++++++++ .../3-transform/client/transform-client.js | 20 ++++++++++++++++++- .../svelte/src/compiler/phases/types.d.ts | 4 ++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 7557b62a8e..499a071270 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -450,7 +450,8 @@ export function analyze_component(root, source, options) { source, undefined_exports: new Map(), snippet_renderers: new Map(), - snippets: new Set() + snippets: new Set(), + is_async: false }; if (!runes) { 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 633a496e05..f8e4cb6ab8 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitExpression.js @@ -6,9 +6,17 @@ * @param {Context} context */ export function AwaitExpression(node, context) { + if (!context.state.analysis.runes) { + throw new Error('TODO runes mode only'); + } + if (context.state.expression) { context.state.expression.is_async = true; } + if (context.state.ast_type === 'instance' && context.state.scope.function_depth === 1) { + context.state.analysis.is_async = true; + } + context.next(); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index a1041947a4..d591dbe4e1 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -355,7 +355,7 @@ export function client_component(analysis, options) { const push_args = [b.id('$$props'), b.literal(analysis.runes)]; if (dev) push_args.push(b.id(analysis.name)); - const component_block = b.block([ + let component_block = b.block([ ...store_setup, ...legacy_reactive_declarations, ...group_binding_declarations, @@ -367,6 +367,24 @@ export function client_component(analysis, options) { .../** @type {ESTree.Statement[]} */ (template.body) ]); + if (analysis.is_async) { + const body = b.function_declaration( + b.id('$$body'), + [b.id('$$anchor'), b.id('$$props')], + component_block + ); + body.async = true; + + state.hoisted.push(body); + + component_block = b.block([ + b.var('fragment', b.call('$.comment')), + b.var('node', b.call('$.first_child', b.id('fragment'))), + b.stmt(b.call(body.id, b.id('node'), b.id('$$props'))), + b.stmt(b.call('$.append', b.id('$$anchor'), b.id('fragment'))) + ]); + } + if (!analysis.runes) { // Bind static exports to props so that people can access them with bind:x for (const { name, alias } of analysis.exports) { diff --git a/packages/svelte/src/compiler/phases/types.d.ts b/packages/svelte/src/compiler/phases/types.d.ts index fe32dbba3e..fc60fe3e4e 100644 --- a/packages/svelte/src/compiler/phases/types.d.ts +++ b/packages/svelte/src/compiler/phases/types.d.ts @@ -85,6 +85,10 @@ export interface ComponentAnalysis extends Analysis { * Every snippet that is declared locally */ snippets: Set; + /** + * true if uses top-level await + */ + is_async: boolean; } declare module 'estree' {