Skip to content

fix: allow await in {@const } in more blocks #16568

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 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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/red-phones-brake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

fix: allow `await` in `{@const }` in more blocks
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,11 @@ export function SvelteBoundary(node, context) {
}

context.next();
if (node.fragment.metadata.has_await) {
for (const child of node.fragment.nodes) {
if (child.type === 'SnippetBlock') {
child.body.metadata.has_await = true;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ export function AwaitBlock(node, context) {
const declarations = argument?.declarations ?? [];
const block = /** @type {BlockStatement} */ (then_context.visit(node.then, then_context.state));

then_block = b.arrow(args, b.block([...declarations, ...block.body]));
then_block = b.arrow(
args,
b.block([...declarations, ...block.body]),
node.then.metadata.has_await
);
}

if (node.catch) {
Expand All @@ -53,7 +57,11 @@ export function AwaitBlock(node, context) {
catch_context.visit(node.catch, catch_context.state)
);

catch_block = b.arrow(args, b.block([...declarations, ...block.body]));
catch_block = b.arrow(
args,
b.block([...declarations, ...block.body]),
node.catch.metadata.has_await
);
}

context.state.init.push(
Expand All @@ -63,7 +71,11 @@ export function AwaitBlock(node, context) {
context.state.node,
expression,
node.pending
? b.arrow([b.id('$$anchor')], /** @type {BlockStatement} */ (context.visit(node.pending)))
? b.arrow(
[b.id('$$anchor')],
/** @type {BlockStatement} */ (context.visit(node.pending)),
node.pending.metadata.has_await
)
: b.null,
then_block,
catch_block
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,12 +326,16 @@ export function EachBlock(node, context) {
b.literal(flags),
thunk,
key_function,
b.arrow(render_args, b.block(declarations.concat(block.body)))
b.arrow(render_args, b.block(declarations.concat(block.body)), node.body.metadata.has_await)
];

if (node.fallback) {
args.push(
b.arrow([b.id('$$anchor')], /** @type {BlockStatement} */ (context.visit(node.fallback)))
b.arrow(
[b.id('$$anchor')],
/** @type {BlockStatement} */ (context.visit(node.fallback)),
node.fallback.metadata.has_await
)
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export function Fragment(node, context) {
const is_single_child_not_needing_template =
trimmed.length === 1 &&
(trimmed[0].type === 'SvelteFragment' || trimmed[0].type === 'TitleElement');
const has_await = context.state.init !== null && (node.metadata.has_await || false);
const has_await =
node.metadata.has_await && !(parent.type === 'Root' && parent.fragment === node);

const template_name = context.state.scope.root.unique('root'); // TODO infer name from parent
const unsuspend = b.id('$$unsuspend');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,21 @@ export function IfBlock(node, context) {
const consequent = /** @type {BlockStatement} */ (context.visit(node.consequent));
const consequent_id = b.id(context.state.scope.generate('consequent'));

statements.push(b.var(consequent_id, b.arrow([b.id('$$anchor')], consequent)));
statements.push(
b.var(
consequent_id,
b.arrow([b.id('$$anchor')], consequent, node.consequent.metadata.has_await)
)
);

let alternate_id;

if (node.alternate) {
const alternate = /** @type {BlockStatement} */ (context.visit(node.alternate));
alternate_id = b.id(context.state.scope.generate('alternate'));
statements.push(b.var(alternate_id, b.arrow([b.id('$$anchor')], alternate)));
statements.push(
b.var(alternate_id, b.arrow([b.id('$$anchor')], alternate, node.alternate.metadata.has_await))
);
}

const { has_await } = node.metadata.expression;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ export function KeyBlock(node, context) {
const body = /** @type {Expression} */ (context.visit(node.fragment));

let statement = add_svelte_meta(
b.call('$.key', context.state.node, key, b.arrow([b.id('$$anchor')], body)),
b.call(
'$.key',
context.state.node,
key,
b.arrow([b.id('$$anchor')], body, node.fragment.metadata.has_await)
),
node,
'key'
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function SnippetBlock(node, context) {
// TODO hoist where possible
/** @type {(Identifier | AssignmentPattern)[]} */
const args = [b.id('$$anchor')];
const has_await = node.body.metadata.has_await || false;
const has_await = node.body.metadata.has_await;

/** @type {BlockStatement} */
let body;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import { BlockStatement, Statement, Expression, VariableDeclaration } from 'estree' */
/** @import { BlockStatement, Statement, Expression, VariableDeclaration, ArrowFunctionExpression, FunctionDeclaration } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types' */
import { dev } from '../../../../state.js';
Expand Down Expand Up @@ -60,14 +60,26 @@ export function SvelteBoundary(node, context) {

const snippet = /** @type {VariableDeclaration} */ (statements[0]);

/** @type {FunctionDeclaration | (ArrowFunctionExpression & { body: BlockStatement})} */
const snippet_fn = dev
? // @ts-expect-error we know this shape is correct
snippet.declarations[0].init.arguments[1]
: snippet.declarations[0].init;

snippet_fn.body.body.unshift(
...const_tags.filter((node) => node.type === 'VariableDeclaration')
);
if (node.fragment.metadata.has_await) {
// we have to make sure the `$.suspend` goes before everything else
snippet_fn.body.body.splice(
dev ? 3 : 2,
0,
...const_tags.filter((node) => node.type === 'VariableDeclaration')
);
} else {
snippet_fn.body.body.splice(
dev ? 2 : 1,
0,
...const_tags.filter((node) => node.type === 'VariableDeclaration')
);
}

hoisted.push(snippet);

Expand All @@ -83,10 +95,19 @@ export function SvelteBoundary(node, context) {

const block = /** @type {BlockStatement} */ (context.visit({ ...node.fragment, nodes }));

block.body.unshift(...const_tags);
if (!node.fragment.metadata.has_await) {
block.body.unshift(...const_tags);
} else {
block.body.splice(1, 0, ...const_tags);
}

const boundary = b.stmt(
b.call('$.boundary', context.state.node, props, b.arrow([b.id('$$anchor')], block))
b.call(
'$.boundary',
context.state.node,
props,
b.arrow([b.id('$$anchor')], block, node.fragment.metadata.has_await)
)
);

context.state.template.push_comment();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ export default test({
async test({ assert, target }) {
await tick();

assert.htmlEqual(target.innerHTML, `<h1>Hello, world!</h1>`);
assert.htmlEqual(target.innerHTML, `<h1>Hello, world!</h1> 5 01234`);
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@
</script>

<svelte:boundary>
{@const number = await Promise.resolve(5)}
{#snippet pending()}
<h1>Loading...</h1>
{/snippet}

{#snippet greet()}
{@const greeting = await `Hello, ${name}!`}
<h1>{greeting}</h1>
{number}
{#if number > 4}
{#each { length: number }, index}
{@const i = await index}
{i}
{/each}
{/if}
{/snippet}

{@render greet()}
Expand Down
Loading