@@ -11,6 +11,7 @@ import {
11
11
ExpressionStatement ,
12
12
ArrowFunctionExpression ,
13
13
ExportSpecifier ,
14
+ Function as FunctionNode ,
14
15
TSType ,
15
16
TSTypeLiteral ,
16
17
TSFunctionType ,
@@ -87,7 +88,8 @@ export function compileScript(
87
88
const setupExports : Record < string , boolean > = { }
88
89
let exportAllIndex = 0
89
90
let defaultExport : Node | undefined
90
- let needDefaultExportRefCheck : boolean = false
91
+ let needDefaultExportRefCheck = false
92
+ let hasAwait = false
91
93
92
94
const checkDuplicateDefaultExport = ( node : Node ) => {
93
95
if ( defaultExport ) {
@@ -230,7 +232,11 @@ export function compileScript(
230
232
231
233
// 3. parse <script setup> and walk over top level statements
232
234
for ( const node of parse ( scriptSetup . content , {
233
- plugins,
235
+ plugins : [
236
+ ...plugins ,
237
+ // allow top level await but only inside <script setup>
238
+ 'topLevelAwait'
239
+ ] ,
234
240
sourceType : 'module'
235
241
} ) . program . body ) {
236
242
const start = node . start ! + startOffset
@@ -439,6 +445,27 @@ export function compileScript(
439
445
recordType ( node , declaredTypes )
440
446
s . move ( start , end , 0 )
441
447
}
448
+
449
+ // walk statements & named exports / variable declarations for top level
450
+ // await
451
+ if (
452
+ node . type === 'VariableDeclaration' ||
453
+ ( node . type === 'ExportNamedDeclaration' &&
454
+ node . declaration &&
455
+ node . declaration . type === 'VariableDeclaration' ) ||
456
+ node . type . endsWith ( 'Statement' )
457
+ ) {
458
+ ; ( walk as any ) ( node , {
459
+ enter ( node : Node ) {
460
+ if ( isFunction ( node ) ) {
461
+ this . skip ( )
462
+ }
463
+ if ( node . type === 'AwaitExpression' ) {
464
+ hasAwait = true
465
+ }
466
+ }
467
+ } )
468
+ }
442
469
}
443
470
444
471
// 4. check default export to make sure it doesn't reference setup scope
@@ -503,7 +530,10 @@ export function compileScript(
503
530
// 6. wrap setup code with function.
504
531
// export the content of <script setup> as a named export, `setup`.
505
532
// this allows `import { setup } from '*.vue'` for testing purposes.
506
- s . prependLeft ( startOffset , `\nexport function setup(${ args } ) {\n` )
533
+ s . prependLeft (
534
+ startOffset ,
535
+ `\nexport ${ hasAwait ? `async ` : `` } function setup(${ args } ) {\n`
536
+ )
507
537
508
538
// generate return statement
509
539
let returned = `{ ${ Object . keys ( setupExports ) . join ( ', ' ) } }`
@@ -867,11 +897,7 @@ function checkDefaultExport(
867
897
)
868
898
)
869
899
}
870
- } else if (
871
- node . type === 'FunctionDeclaration' ||
872
- node . type === 'FunctionExpression' ||
873
- node . type === 'ArrowFunctionExpression'
874
- ) {
900
+ } else if ( isFunction ( node ) ) {
875
901
// walk function expressions and add its arguments to known identifiers
876
902
// so that we don't prefix them
877
903
node . params . forEach ( p =>
@@ -927,6 +953,10 @@ function isStaticPropertyKey(node: Node, parent: Node): boolean {
927
953
)
928
954
}
929
955
956
+ function isFunction ( node : Node ) : node is FunctionNode {
957
+ return / F u n c t i o n (?: E x p r e s s i o n | D e c l a r a t i o n ) $ | M e t h o d $ / . test ( node . type )
958
+ }
959
+
930
960
/**
931
961
* Analyze bindings in normal `<script>`
932
962
* Note that `compileScriptSetup` already analyzes bindings as part of its
0 commit comments