Skip to content

feat: allow await in components #15844

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 389 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
389 commits
Select commit Hold shift + click to select a range
b9a3f1e
cleanup and simplify
trueadm Jan 25, 2025
5a4b11b
fix leak
trueadm Jan 27, 2025
1c4db3d
hoist functions, use names to make stuff a little clearer
Rich-Harris Jan 28, 2025
36e281c
boundary_fn -> children
Rich-Harris Jan 28, 2025
adb1375
rename async_effect/fragment to offscreen_effect/fragment — much clea…
Rich-Harris Jan 28, 2025
6b5d6c0
remove unnecessary function wrapper
Rich-Harris Jan 28, 2025
9c00acd
no need to explicitly remove
Rich-Harris Jan 28, 2025
91d09b0
unused
Rich-Harris Jan 28, 2025
29a47c2
type annotation is unnecessary
Rich-Harris Jan 28, 2025
056601f
there's no point passing to , it's unused
Rich-Harris Jan 28, 2025
036001c
turn on hmr
trueadm Jan 28, 2025
cfba900
represent main/pending/failed effects separately, as we do for other …
Rich-Harris Jan 28, 2025
422e658
Merge branch 'main' into aa
Rich-Harris Jan 28, 2025
2b08128
step one - template effects
Rich-Harris Jan 28, 2025
41314a6
WIP
Rich-Harris Jan 28, 2025
ce34c76
update tests
Rich-Harris Jan 28, 2025
ca11ebd
fix
Rich-Harris Jan 28, 2025
42a59e2
fix
Rich-Harris Jan 28, 2025
f38bd5c
key blocks
Rich-Harris Jan 29, 2025
a6d3f85
merge main
Rich-Harris Jan 29, 2025
4642b49
merge aa
Rich-Harris Jan 29, 2025
2c557b6
html tags
Rich-Harris Jan 29, 2025
a79dfb5
fix conflict
trueadm Jan 30, 2025
6117037
fix HMR bug
trueadm Jan 30, 2025
5530ae5
disable hmr for now
Rich-Harris Jan 30, 2025
5b0b9eb
debugging utils
Rich-Harris Jan 30, 2025
9d9198a
tweak
Rich-Harris Jan 30, 2025
4588ad6
Merge branch 'main' into aa
Rich-Harris Jan 30, 2025
3763ff3
Merge branch 'aa' into aa-coordination
Rich-Harris Jan 30, 2025
877a417
move code
Rich-Harris Jan 30, 2025
da5ff88
cordon off hydration code
Rich-Harris Jan 30, 2025
303d738
add should_defer_append flag
Rich-Harris Jan 30, 2025
ffc4f1b
mostly working
Rich-Harris Jan 30, 2025
70fa103
simplify
Rich-Harris Jan 30, 2025
176ec0d
fix
Rich-Harris Jan 30, 2025
2e49f7c
tidy
Rich-Harris Jan 30, 2025
af2224e
tidy up
Rich-Harris Jan 30, 2025
c270c76
fix timing
Rich-Harris Jan 31, 2025
f2002ce
fix
Rich-Harris Jan 31, 2025
b5df097
fixes
Rich-Harris Jan 31, 2025
952ea25
failing test
Rich-Harris Jan 31, 2025
010108a
hoist commit logic
Rich-Harris Jan 31, 2025
028dba8
each blocks work!
Rich-Harris Jan 31, 2025
012cdeb
fix
Rich-Harris Jan 31, 2025
6025193
partial fix
Rich-Harris Jan 31, 2025
0ace243
fix
Rich-Harris Jan 31, 2025
6e1a331
tidy up
Rich-Harris Jan 31, 2025
5f61b08
simplify
Rich-Harris Jan 31, 2025
a405d47
remove unnecessary TEMPLATE_EFFECT distinction
Rich-Harris Jan 31, 2025
7e337bc
unused
Rich-Harris Jan 31, 2025
09cf66c
simplify
Rich-Harris Jan 31, 2025
b4ee140
Merge branch 'main' into aa-coordination
Rich-Harris Jan 31, 2025
148ffd2
warn on reactivity loss
Rich-Harris Jan 31, 2025
51e50ec
add test, tidy up
Rich-Harris Jan 31, 2025
5969b09
waterfall detection
Rich-Harris Jan 31, 2025
d155191
fix
Rich-Harris Feb 2, 2025
c9d6195
make purpose explicit
Rich-Harris Feb 2, 2025
c56ee71
add showPendingAfter and showPendingFor
Rich-Harris Feb 3, 2025
0a5628f
improve waterfall detection
Rich-Harris Feb 3, 2025
80b713a
abort component if already destroyed
Rich-Harris Feb 3, 2025
0dc84ab
only suspend in top-level async deriveds
Rich-Harris Feb 3, 2025
cc7bc32
merge main
Rich-Harris Feb 3, 2025
c2869f5
bump
Rich-Harris Feb 3, 2025
5f2abc8
skip adding dependencies for destroyed effects
Rich-Harris Feb 3, 2025
b64cfc6
update comment
Rich-Harris Feb 3, 2025
8055046
dont reconnect deriveds inside destroyed effects
Rich-Harris Feb 4, 2025
e69d85b
Merge branch 'main' into aa-coordination
trueadm Feb 4, 2025
ff5d9fe
pending_items -> offscreen_items
Rich-Harris Feb 4, 2025
990634d
remove old comment
Rich-Harris Feb 4, 2025
ae8bd6f
fix await member expressions
trueadm Feb 4, 2025
68a10b7
Merge branch 'main' into async
Rich-Harris Feb 5, 2025
994afaf
Revert "fix await member expressions"
Rich-Harris Feb 5, 2025
bcdddc6
fix member expressions for real
Rich-Harris Feb 5, 2025
2703ac6
fix heuristic for transforming await expressions on server
Rich-Harris Feb 5, 2025
726b3f1
delay initial async derived resolution if invalidated during init
Rich-Harris Feb 5, 2025
69a1902
small fix
Rich-Harris Feb 5, 2025
461c081
error handling
Rich-Harris Feb 6, 2025
0b9bfc9
async derived cannot use $derived.by
Rich-Harris Feb 6, 2025
3289ac3
slightly better waterfall warning
Rich-Harris Feb 6, 2025
7bd6969
fix
Rich-Harris Feb 11, 2025
7bf7e0d
start converting boundary to a class
Rich-Harris Feb 11, 2025
ba957b6
unused
Rich-Harris Feb 11, 2025
fe3b177
more
Rich-Harris Feb 11, 2025
7b2c677
unused
Rich-Harris Feb 11, 2025
66f0f1b
more
Rich-Harris Feb 11, 2025
31a9844
more
Rich-Harris Feb 11, 2025
2e65e6e
more
Rich-Harris Feb 11, 2025
e996219
more
Rich-Harris Feb 11, 2025
eb465b5
more
Rich-Harris Feb 11, 2025
85fa872
unused
Rich-Harris Feb 11, 2025
72ab4fc
more
Rich-Harris Feb 11, 2025
7e26a83
simplify
Rich-Harris Feb 11, 2025
4a9ff23
more
Rich-Harris Feb 11, 2025
6b05852
more
Rich-Harris Feb 11, 2025
8c727cc
more
Rich-Harris Feb 11, 2025
1e56ce2
unused
Rich-Harris Feb 11, 2025
4c04053
more
Rich-Harris Feb 11, 2025
9cc52e2
simplify
Rich-Harris Feb 11, 2025
1f58d6b
simplify
Rich-Harris Feb 11, 2025
58dc13e
unused
Rich-Harris Feb 11, 2025
67b5c09
more
Rich-Harris Feb 11, 2025
3b9349e
tweak
Rich-Harris Feb 11, 2025
63be623
unused
Rich-Harris Feb 11, 2025
30cd46d
more
Rich-Harris Feb 11, 2025
df027d0
shuffle
Rich-Harris Feb 11, 2025
a4540f8
merge main
Rich-Harris Feb 11, 2025
366b59c
move compiler options to svelte.config.js, to remove red squigglies i…
Rich-Harris Feb 13, 2025
ef28490
merge main
Rich-Harris Feb 13, 2025
9d7d045
create separate effect type for async deriveds, as they are not blocks
Rich-Harris Feb 13, 2025
7923b5a
simplify
Rich-Harris Feb 13, 2025
b18247b
WIP
Rich-Harris Feb 19, 2025
120b086
WIP
Rich-Harris Feb 19, 2025
0bc2af2
WIP
Rich-Harris Feb 20, 2025
2fbf290
WIP
Rich-Harris Feb 20, 2025
6f32d21
merge main
Rich-Harris Feb 20, 2025
8aaa568
Merge branch 'async' into async-global-coordination
Rich-Harris Feb 20, 2025
0e4f041
WIP
Rich-Harris Feb 20, 2025
f9eb2f9
mirror some changes from main
Rich-Harris Feb 24, 2025
892dc82
rename
Rich-Harris Feb 24, 2025
527deea
more
Rich-Harris Feb 24, 2025
5d9bd7f
more
Rich-Harris Feb 24, 2025
ed50a6b
more
Rich-Harris Feb 24, 2025
db94790
more
Rich-Harris Feb 24, 2025
cbc227c
more
Rich-Harris Feb 24, 2025
92b03ce
merge main
Rich-Harris Feb 24, 2025
dd9bb71
merge async
Rich-Harris Feb 24, 2025
1f4be94
move some stuff
Rich-Harris Feb 24, 2025
97587c3
WIP
Rich-Harris Feb 24, 2025
c6d9110
some progress
Rich-Harris Feb 24, 2025
29906c5
partial fix
Rich-Harris Feb 24, 2025
8e90bb2
remove unused test
Rich-Harris Feb 24, 2025
14330bd
add Promise.withResolvers shim for convenience
Rich-Harris Feb 24, 2025
f77df36
WIP
Rich-Harris Feb 24, 2025
7e0fdb5
update tests
Rich-Harris Feb 24, 2025
ba68a93
update test
Rich-Harris Feb 24, 2025
fde316f
fix
Rich-Harris Feb 24, 2025
807a585
tidy up
Rich-Harris Feb 24, 2025
b0b37e6
partial fix
Rich-Harris Feb 26, 2025
9e877be
fix
Rich-Harris Feb 26, 2025
57232ee
fix
Rich-Harris Feb 26, 2025
2b2cdf1
fix
Rich-Harris Feb 26, 2025
710ae62
fix
Rich-Harris Feb 26, 2025
b18cd46
update tests
Rich-Harris Feb 26, 2025
a5275b2
update test, remove unnecessary suspend
Rich-Harris Feb 26, 2025
4e417e1
fix
Rich-Harris Feb 26, 2025
f90132c
fix
Rich-Harris Feb 26, 2025
ac33857
fix
Rich-Harris Feb 26, 2025
9b36b6b
add callsite to effect tree logs
Rich-Harris Feb 27, 2025
3c350db
fix
Rich-Harris Feb 27, 2025
8a96f23
tidy
Rich-Harris Feb 27, 2025
eb8c8e6
simplify
Rich-Harris Feb 27, 2025
52d4ade
simplify
Rich-Harris Feb 27, 2025
47a1693
fix
Rich-Harris Feb 27, 2025
94da28f
skip test
Rich-Harris Feb 27, 2025
ee71311
fix
Rich-Harris Feb 28, 2025
a0a4d4f
fix
Rich-Harris Feb 28, 2025
31882d1
add `$effect.pending()`
Rich-Harris Feb 28, 2025
49480f0
try this
Rich-Harris Feb 28, 2025
5bcdb13
fix
Rich-Harris Feb 28, 2025
3d970d2
merge main -> async
Rich-Harris Apr 16, 2025
3decb67
add TODO
Rich-Harris Apr 16, 2025
8ba4f71
Merge branch 'main' into async
Rich-Harris Apr 16, 2025
90cdc16
align with main
Rich-Harris Apr 16, 2025
02efac9
fix
Rich-Harris Apr 16, 2025
d5922f8
merge main
Rich-Harris Apr 16, 2025
fcbb54d
merge main
Rich-Harris Apr 17, 2025
888fc31
is_async -> has_await
Rich-Harris Apr 17, 2025
4b7130e
merge main
Rich-Harris Apr 17, 2025
94a4b11
Merge branch 'main' into async
Rich-Harris Apr 18, 2025
ab0ec6f
don't update a focused input (may need to add a blur handler later, w…
Rich-Harris Apr 18, 2025
cc2b888
merge main
Rich-Harris Apr 18, 2025
521b228
docs
Rich-Harris Apr 18, 2025
037e289
fix
Rich-Harris Apr 18, 2025
6688eb8
remove indirection
Rich-Harris Apr 18, 2025
cb2f68e
QOL
Rich-Harris Apr 18, 2025
4f45033
move stuff
Rich-Harris Apr 18, 2025
a469c39
update test to not rely on props
Rich-Harris Apr 19, 2025
43457cc
.
Rich-Harris Apr 19, 2025
8b691e9
rename
Rich-Harris Apr 19, 2025
81f066f
update test
Rich-Harris Apr 19, 2025
a840f00
tweak
Rich-Harris Apr 19, 2025
3fe77cd
tweak
Rich-Harris Apr 19, 2025
b7c3995
tweak
Rich-Harris Apr 19, 2025
2620a21
tweak
Rich-Harris Apr 19, 2025
0abc0a8
tweak
Rich-Harris Apr 19, 2025
2797036
Merge branch 'main' into async
Rich-Harris Apr 19, 2025
ce09353
tidy up
Rich-Harris Apr 19, 2025
e49f81f
dont use flushSync
Rich-Harris Apr 19, 2025
e0e48b3
WIP
Rich-Harris Apr 19, 2025
8cc5961
tweak
Rich-Harris Apr 20, 2025
b48c12b
out of date
Rich-Harris Apr 20, 2025
e247f66
more
Rich-Harris Apr 20, 2025
d42b358
guarantee fork
Rich-Harris Apr 20, 2025
5000aae
forks.js -> batch.js
Rich-Harris Apr 20, 2025
d465537
rename forks to batches
Rich-Harris Apr 20, 2025
9b5f00b
fix
Rich-Harris Apr 20, 2025
5a3f7c2
simplify
Rich-Harris Apr 20, 2025
011741e
note to self
Rich-Harris Apr 20, 2025
623fb50
tweak
Rich-Harris Apr 20, 2025
4a56c2a
tweak
Rich-Harris Apr 20, 2025
f30fd26
privatise
Rich-Harris Apr 20, 2025
6eac199
failing test
Rich-Harris Apr 20, 2025
1f02fdf
note to self
Rich-Harris Apr 20, 2025
3ee25bb
reinstate scheduling optimisation
Rich-Harris Apr 20, 2025
e5579fd
WIP
Rich-Harris Apr 20, 2025
2e813f1
consistent behaviour
Rich-Harris Apr 20, 2025
6e26478
simplify
Rich-Harris Apr 20, 2025
5518e98
WIP
Rich-Harris Apr 20, 2025
c0ff1d0
tidy
Rich-Harris Apr 20, 2025
0f5b3cd
tweak
Rich-Harris Apr 21, 2025
32f753d
fix
Rich-Harris Apr 21, 2025
f73a5e9
compile playground with dev: false
Rich-Harris Apr 21, 2025
2087b3e
failing test
Rich-Harris Apr 21, 2025
ec81491
shuffle
Rich-Harris Apr 21, 2025
45f4cc5
WIP
Rich-Harris Apr 21, 2025
9e0bd4f
WIP
Rich-Harris Apr 21, 2025
0bc6e69
WIP
Rich-Harris Apr 21, 2025
43eeca9
WIP
Rich-Harris Apr 21, 2025
1cb4e24
WIP
Rich-Harris Apr 21, 2025
21e4c44
WIP
Rich-Harris Apr 21, 2025
1c31363
WIP
Rich-Harris Apr 21, 2025
4680f38
WIP
Rich-Harris Apr 21, 2025
29147fb
WIP
Rich-Harris Apr 21, 2025
abba96c
WIP
Rich-Harris Apr 21, 2025
6f8abda
fix
Rich-Harris Apr 21, 2025
48293d2
fix
Rich-Harris Apr 21, 2025
d7d528c
fix `$effect.pending()`
Rich-Harris Apr 23, 2025
b805245
fix
Rich-Harris Apr 25, 2025
734f56c
fix
Rich-Harris Apr 28, 2025
77e0e60
merge main
Rich-Harris Apr 28, 2025
d7f580d
fix changeset
Rich-Harris Apr 30, 2025
399bda5
lint
Rich-Harris May 3, 2025
a98b5ea
note to self
Rich-Harris May 3, 2025
fc18e26
failing test
Rich-Harris May 3, 2025
ed17212
fix
Rich-Harris May 3, 2025
78dd1e2
DRY
Rich-Harris May 3, 2025
13a9b70
failing test for linear order
Rich-Harris May 3, 2025
1dd383e
enforce linear order
Rich-Harris May 3, 2025
7762f29
update test
Rich-Harris May 4, 2025
8baf164
fix
Rich-Harris May 4, 2025
666a148
implement getAbortSignal
Rich-Harris May 4, 2025
357ff47
docs
Rich-Harris May 4, 2025
b61c6ad
fix
Rich-Harris May 4, 2025
b68dcdc
note to self
Rich-Harris May 4, 2025
5e8bcfa
tweak/fix
Rich-Harris May 4, 2025
3d0b6f7
update test
Rich-Harris May 4, 2025
48a781e
fix
Rich-Harris May 5, 2025
693262a
fix
Rich-Harris May 5, 2025
c599807
implement `settled`
Rich-Harris May 9, 2025
53b9b8f
merge main
Rich-Harris May 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/eleven-weeks-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': minor
---

feat: support `await` in components
16 changes: 16 additions & 0 deletions documentation/docs/98-reference/.generated/client-warnings.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ function add() {
}
```

### await_reactivity_loss

```
Detected reactivity loss
```

TODO

### await_waterfall

```
An async value (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app.
```

TODO

### binding_property_non_reactive

```
Expand Down
12 changes: 12 additions & 0 deletions documentation/docs/98-reference/.generated/compile-errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,12 @@ Expected token %token%
Expected whitespace
```

### experimental_async

```
Cannot use `await` in deriveds and template expressions, or at the top level of a component, unless the `experimental.async` compiler option is `true`
```

### export_undefined

```
Expand Down Expand Up @@ -534,6 +540,12 @@ The arguments keyword cannot be used within the template or at the top level of
%message%
```

### legacy_await_invalid

```
Cannot use `await` in deriveds and template expressions, or at the top level of a component, unless in runes mode
```

### legacy_export_invalid

```
Expand Down
8 changes: 8 additions & 0 deletions documentation/docs/98-reference/.generated/shared-errors.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
<!-- This file is generated by scripts/process-messages/index.js. Do not edit! -->

### await_outside_boundary

```
Cannot await outside a `<svelte:boundary>` with a `pending` snippet
```

TODO

### invalid_default_snippet

```
Expand Down
12 changes: 12 additions & 0 deletions packages/svelte/messages/client-warnings/warnings.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ function add() {
}
```

## await_reactivity_loss

> Detected reactivity loss

TODO

## await_waterfall

> An async value (%location%) was not read immediately after it resolved. This often indicates an unnecessary waterfall, which can slow down your app.

TODO

## binding_property_non_reactive

> `%binding%` is binding to a non-reactive property
Expand Down
8 changes: 8 additions & 0 deletions packages/svelte/messages/compile-errors/script.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ This turned out to be buggy and unpredictable, particularly when working with de

> `$effect()` can only be used as an expression statement

## experimental_async

> Cannot use `await` in deriveds and template expressions, or at the top level of a component, unless the `experimental.async` compiler option is `true`

## export_undefined

> `%name%` is not defined
Expand Down Expand Up @@ -98,6 +102,10 @@ This turned out to be buggy and unpredictable, particularly when working with de

> The arguments keyword cannot be used within the template or at the top level of a component

## legacy_await_invalid

> Cannot use `await` in deriveds and template expressions, or at the top level of a component, unless in runes mode

## legacy_export_invalid

> Cannot use `export let` in runes mode — use `$props()` instead
Expand Down
6 changes: 6 additions & 0 deletions packages/svelte/messages/shared-errors/errors.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## await_outside_boundary

> Cannot await outside a `<svelte:boundary>` with a `pending` snippet

TODO

## invalid_default_snippet

> Cannot use `{@render children(...)}` if the parent component uses `let:` directives. Consider using a named snippet instead
Expand Down
18 changes: 18 additions & 0 deletions packages/svelte/src/compiler/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,15 @@ export function effect_invalid_placement(node) {
e(node, 'effect_invalid_placement', `\`$effect()\` can only be used as an expression statement\nhttps://svelte.dev/e/effect_invalid_placement`);
}

/**
* Cannot use `await` in deriveds and template expressions, or at the top level of a component, unless the `experimental.async` compiler option is `true`
* @param {null | number | NodeLike} node
* @returns {never}
*/
export function experimental_async(node) {
e(node, 'experimental_async', `Cannot use \`await\` in deriveds and template expressions, or at the top level of a component, unless the \`experimental.async\` compiler option is \`true\`\nhttps://svelte.dev/e/experimental_async`);
}

/**
* `%name%` is not defined
* @param {null | number | NodeLike} node
Expand Down Expand Up @@ -233,6 +242,15 @@ export function invalid_arguments_usage(node) {
e(node, 'invalid_arguments_usage', `The arguments keyword cannot be used within the template or at the top level of a component\nhttps://svelte.dev/e/invalid_arguments_usage`);
}

/**
* Cannot use `await` in deriveds and template expressions, or at the top level of a component, unless in runes mode
* @param {null | number | NodeLike} node
* @returns {never}
*/
export function legacy_await_invalid(node) {
e(node, 'legacy_await_invalid', `Cannot use \`await\` in deriveds and template expressions, or at the top level of a component, unless in runes mode\nhttps://svelte.dev/e/legacy_await_invalid`);
}

/**
* Cannot use `export let` in runes mode — use `$props()` instead
* @param {null | number | NodeLike} node
Expand Down
5 changes: 4 additions & 1 deletion packages/svelte/src/compiler/migrate/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,10 @@ export function migrate(source, { filename, use_ts } = {}) {
...validate_component_options({}, ''),
...parsed_options,
customElementOptions,
filename: filename ?? '(unknown)'
filename: filename ?? '(unknown)',
experimental: {
async: true
}
};

const str = new MagicString(source);
Expand Down
2 changes: 2 additions & 0 deletions packages/svelte/src/compiler/phases/1-parse/state/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ export default function element(parser) {
} else {
element.tag = get_attribute_expression(definition);
}

element.metadata.expression = create_expression_metadata();
}

if (is_top_level_script_or_style) {
Expand Down
20 changes: 16 additions & 4 deletions packages/svelte/src/compiler/phases/1-parse/state/tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ function open(parser) {
end: -1,
test: read_expression(parser),
consequent: create_fragment(),
alternate: null
alternate: null,
metadata: {
expression: create_expression_metadata()
}
});

parser.allow_whitespace();
Expand Down Expand Up @@ -326,7 +329,10 @@ function open(parser) {
start,
end: -1,
expression,
fragment: create_fragment()
fragment: create_fragment(),
metadata: {
expression: create_expression_metadata()
}
});

parser.stack.push(block);
Expand Down Expand Up @@ -461,7 +467,10 @@ function next(parser) {
elseif: true,
test: expression,
consequent: create_fragment(),
alternate: null
alternate: null,
metadata: {
expression: create_expression_metadata()
}
});

parser.stack.push(child);
Expand Down Expand Up @@ -624,7 +633,10 @@ function special(parser) {
type: 'HtmlTag',
start,
end: parser.index,
expression
expression,
metadata: {
expression: create_expression_metadata()
}
});

return;
Expand Down
32 changes: 25 additions & 7 deletions packages/svelte/src/compiler/phases/2-analyze/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { AssignmentExpression } from './visitors/AssignmentExpression.js';
import { AttachTag } from './visitors/AttachTag.js';
import { Attribute } from './visitors/Attribute.js';
import { AwaitBlock } from './visitors/AwaitBlock.js';
import { AwaitExpression } from './visitors/AwaitExpression.js';
import { BindDirective } from './visitors/BindDirective.js';
import { CallExpression } from './visitors/CallExpression.js';
import { ClassBody } from './visitors/ClassBody.js';
Expand Down Expand Up @@ -138,6 +139,7 @@ const visitors = {
AttachTag,
Attribute,
AwaitBlock,
AwaitExpression,
BindDirective,
CallExpression,
ClassBody,
Expand Down Expand Up @@ -209,9 +211,14 @@ function js(script, root, allow_reactive_declarations, parent) {
body: []
};

const { scope, scopes } = create_scopes(ast, root, allow_reactive_declarations, parent);
const { scope, scopes, has_await } = create_scopes(
ast,
root,
allow_reactive_declarations,
parent
);

return { ast, scope, scopes };
return { ast, scope, scopes, has_await };
}

/**
Expand All @@ -236,7 +243,7 @@ const RESERVED = ['$$props', '$$restProps', '$$slots'];
* @returns {Analysis}
*/
export function analyze_module(ast, options) {
const { scope, scopes } = create_scopes(ast, new ScopeRoot(), false, null);
const { scope, scopes, has_await } = create_scopes(ast, new ScopeRoot(), false, null);

for (const [name, references] of scope.references) {
if (name[0] !== '$' || RESERVED.includes(name)) continue;
Expand All @@ -253,12 +260,14 @@ export function analyze_module(ast, options) {

/** @type {Analysis} */
const analysis = {
module: { ast, scope, scopes },
module: { ast, scope, scopes, has_await },
name: options.filename,
accessors: false,
runes: true,
immutable: true,
tracing: false,
async_deriveds: new Set(),
context_preserving_awaits: new Set(),
classes: new Map()
};

Expand Down Expand Up @@ -298,7 +307,12 @@ export function analyze_component(root, source, options) {
const module = js(root.module, scope_root, false, null);
const instance = js(root.instance, scope_root, true, module.scope);

const { scope, scopes } = create_scopes(root.fragment, scope_root, false, instance.scope);
const { scope, scopes, has_await } = create_scopes(
root.fragment,
scope_root,
false,
instance.scope
);

/** @type {Template} */
const template = { ast: root.fragment, scope, scopes };
Expand Down Expand Up @@ -406,7 +420,9 @@ export function analyze_component(root, source, options) {

const component_name = get_component_name(options.filename);

const runes = options.runes ?? Array.from(module.scope.references.keys()).some(is_rune);
const runes =
options.runes ??
(has_await || instance.has_await || Array.from(module.scope.references.keys()).some(is_rune));

if (!runes) {
for (let check of synthetic_stores_legacy_check) {
Expand Down Expand Up @@ -472,7 +488,9 @@ export function analyze_component(root, source, options) {
source,
undefined_exports: new Map(),
snippet_renderers: new Map(),
snippets: new Set()
snippets: new Set(),
async_deriveds: new Set(),
context_preserving_awaits: new Set()
};

if (!runes) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/** @import { AwaitExpression } from 'estree' */
/** @import { Context } from '../types' */
import * as e from '../../../errors.js';

/**
* @param {AwaitExpression} node
* @param {Context} context
*/
export function AwaitExpression(node, context) {
const tla = context.state.ast_type === 'instance' && context.state.function_depth === 1;
let suspend = tla;
let preserve_context = tla;

if (context.state.expression) {
context.state.expression.has_await = true;
suspend = true;

// wrap the expression in `(await $.save(...)).restore()` if necessary,
// i.e. whether anything could potentially be read _after_ the await
let i = context.path.length;
while (i--) {
const parent = context.path[i];

// stop walking up when we find a node with metadata, because that
// means we've hit the template node containing the expression
// @ts-expect-error we could probably use a neater/more robust mechanism
if (parent.metadata) break;

// TODO make this more accurate — we don't need to call suspend
// if this is the last thing that could be read
preserve_context = true;
}
}

if (suspend) {
if (!context.state.options.experimental.async) {
e.experimental_async(node);
}

if (!context.state.analysis.runes) {
e.legacy_await_invalid(node);
}
}

if (preserve_context) {
context.state.analysis.context_preserving_awaits.add(node);
}

context.next();
}
Loading
Loading