Skip to content

Commit f2dd477

Browse files
authored
fix: await blockers before initialising const (#17226)
* fix: await blockers before initialising const Fixes #17224 * ssr + test
1 parent 707b6b8 commit f2dd477

File tree

5 files changed

+31
-8
lines changed

5 files changed

+31
-8
lines changed

.changeset/famous-terms-shake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: await blockers before initialising const

packages/svelte/src/compiler/phases/3-transform/client/visitors/ConstTag.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** @import { Pattern } from 'estree' */
22
/** @import { AST } from '#compiler' */
33
/** @import { ComponentContext } from '../types' */
4+
/** @import { ExpressionMetadata } from '../../../nodes.js' */
45
import { dev } from '../../../../state.js';
56
import { extract_identifiers } from '../../../../utils/ast.js';
67
import * as b from '#compiler/builders';
@@ -30,7 +31,7 @@ export function ConstTag(node, context) {
3031
context.state,
3132
declaration.id,
3233
expression,
33-
node.metadata.expression.has_await,
34+
node.metadata.expression,
3435
context.state.scope.get_bindings(declaration)
3536
);
3637
} else {
@@ -73,7 +74,7 @@ export function ConstTag(node, context) {
7374
context.state,
7475
tmp,
7576
expression,
76-
node.metadata.expression.has_await,
77+
node.metadata.expression,
7778
context.state.scope.get_bindings(declaration)
7879
);
7980

@@ -89,15 +90,18 @@ export function ConstTag(node, context) {
8990
* @param {ComponentContext['state']} state
9091
* @param {import('estree').Identifier} id
9192
* @param {import('estree').Expression} expression
92-
* @param {boolean} has_await
93+
* @param {ExpressionMetadata} metadata
9394
* @param {import('#compiler').Binding[]} bindings
9495
*/
95-
function add_const_declaration(state, id, expression, has_await, bindings) {
96+
function add_const_declaration(state, id, expression, metadata, bindings) {
9697
// we need to eagerly evaluate the expression in order to hit any
9798
// 'Cannot access x before initialization' errors
9899
const after = dev ? [b.stmt(b.call('$.get', id))] : [];
99100

100-
if (has_await || state.async_consts) {
101+
const has_await = metadata.has_await;
102+
const blockers = [...metadata.dependencies].map((dep) => dep.blocker).filter((b) => b !== null);
103+
104+
if (has_await || state.async_consts || blockers.length > 0) {
101105
const run = (state.async_consts ??= {
102106
id: b.id(state.scope.generate('promises')),
103107
thunks: []
@@ -108,6 +112,8 @@ function add_const_declaration(state, id, expression, has_await, bindings) {
108112
const assignment = b.assignment('=', id, expression);
109113
const body = after.length === 0 ? assignment : b.block([b.stmt(assignment), ...after]);
110114

115+
if (blockers.length > 0) run.thunks.push(b.thunk(b.call('Promise.all', b.array(blockers))));
116+
111117
run.thunks.push(b.thunk(body, has_await));
112118

113119
const blocker = b.member(run.id, b.literal(run.thunks.length - 1), true);

packages/svelte/src/compiler/phases/3-transform/server/visitors/ConstTag.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ export function ConstTag(node, context) {
1313
const id = /** @type {Pattern} */ (context.visit(declaration.id));
1414
const init = /** @type {Expression} */ (context.visit(declaration.init));
1515
const has_await = node.metadata.expression.has_await;
16+
const blockers = [...node.metadata.expression.dependencies]
17+
.map((dep) => dep.blocker)
18+
.filter((b) => b !== null);
1619

17-
if (has_await || context.state.async_consts) {
20+
if (has_await || context.state.async_consts || blockers.length > 0) {
1821
const run = (context.state.async_consts ??= {
1922
id: b.id(context.state.scope.generate('promises')),
2023
thunks: []
@@ -27,6 +30,10 @@ export function ConstTag(node, context) {
2730
context.state.init.push(b.let(identifier.name));
2831
}
2932

33+
if (blockers.length > 0) {
34+
run.thunks.push(b.thunk(b.call('Promise.all', b.array(blockers))));
35+
}
36+
3037
const assignment = b.assignment('=', id, init);
3138
run.thunks.push(b.thunk(b.block([b.stmt(assignment)]), has_await));
3239

packages/svelte/tests/runtime-runes/samples/async-const/_config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import { test } from '../../test';
33

44
export default test({
55
mode: ['async-server', 'client', 'hydrate'],
6-
ssrHtml: `<h1>Hello, world!</h1> 5 01234 5 sync 6 5 0`,
6+
ssrHtml: `<h1>Hello, world!</h1> 5 01234 5 sync 6 5 0 10`,
77

88
async test({ assert, target }) {
99
await tick();
1010

11-
assert.htmlEqual(target.innerHTML, `<h1>Hello, world!</h1> 5 01234 5 sync 6 5 0`);
11+
assert.htmlEqual(target.innerHTML, `<h1>Hello, world!</h1> 5 01234 5 sync 6 5 0 10`);
1212
}
1313
});

packages/svelte/tests/runtime-runes/samples/async-const/main.svelte

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,9 @@
2323

2424
{@render greet()}
2525
{number} {sync} {after_async} {length} {first}
26+
27+
{#if sync}
28+
{@const double = number * 2}
29+
{double}
30+
{/if}
2631
</svelte:boundary>

0 commit comments

Comments
 (0)