fix: await blockers before initialising const (#17226)

* fix: await blockers before initialising const

Fixes #17224

* ssr + test
pull/17245/head
Simon H 5 months ago committed by GitHub
parent 707b6b8c20
commit f2dd477031
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: await blockers before initialising const

@ -1,6 +1,7 @@
/** @import { Pattern } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types' */
/** @import { ExpressionMetadata } from '../../../nodes.js' */
import { dev } from '../../../../state.js';
import { extract_identifiers } from '../../../../utils/ast.js';
import * as b from '#compiler/builders';
@ -30,7 +31,7 @@ export function ConstTag(node, context) {
context.state,
declaration.id,
expression,
node.metadata.expression.has_await,
node.metadata.expression,
context.state.scope.get_bindings(declaration)
);
} else {
@ -73,7 +74,7 @@ export function ConstTag(node, context) {
context.state,
tmp,
expression,
node.metadata.expression.has_await,
node.metadata.expression,
context.state.scope.get_bindings(declaration)
);
@ -89,15 +90,18 @@ export function ConstTag(node, context) {
* @param {ComponentContext['state']} state
* @param {import('estree').Identifier} id
* @param {import('estree').Expression} expression
* @param {boolean} has_await
* @param {ExpressionMetadata} metadata
* @param {import('#compiler').Binding[]} bindings
*/
function add_const_declaration(state, id, expression, has_await, bindings) {
function add_const_declaration(state, id, expression, metadata, bindings) {
// we need to eagerly evaluate the expression in order to hit any
// 'Cannot access x before initialization' errors
const after = dev ? [b.stmt(b.call('$.get', id))] : [];
if (has_await || state.async_consts) {
const has_await = metadata.has_await;
const blockers = [...metadata.dependencies].map((dep) => dep.blocker).filter((b) => b !== null);
if (has_await || state.async_consts || blockers.length > 0) {
const run = (state.async_consts ??= {
id: b.id(state.scope.generate('promises')),
thunks: []
@ -108,6 +112,8 @@ function add_const_declaration(state, id, expression, has_await, bindings) {
const assignment = b.assignment('=', id, expression);
const body = after.length === 0 ? assignment : b.block([b.stmt(assignment), ...after]);
if (blockers.length > 0) run.thunks.push(b.thunk(b.call('Promise.all', b.array(blockers))));
run.thunks.push(b.thunk(body, has_await));
const blocker = b.member(run.id, b.literal(run.thunks.length - 1), true);

@ -13,8 +13,11 @@ export function ConstTag(node, context) {
const id = /** @type {Pattern} */ (context.visit(declaration.id));
const init = /** @type {Expression} */ (context.visit(declaration.init));
const has_await = node.metadata.expression.has_await;
const blockers = [...node.metadata.expression.dependencies]
.map((dep) => dep.blocker)
.filter((b) => b !== null);
if (has_await || context.state.async_consts) {
if (has_await || context.state.async_consts || blockers.length > 0) {
const run = (context.state.async_consts ??= {
id: b.id(context.state.scope.generate('promises')),
thunks: []
@ -27,6 +30,10 @@ export function ConstTag(node, context) {
context.state.init.push(b.let(identifier.name));
}
if (blockers.length > 0) {
run.thunks.push(b.thunk(b.call('Promise.all', b.array(blockers))));
}
const assignment = b.assignment('=', id, init);
run.thunks.push(b.thunk(b.block([b.stmt(assignment)]), has_await));

@ -3,11 +3,11 @@ import { test } from '../../test';
export default test({
mode: ['async-server', 'client', 'hydrate'],
ssrHtml: `<h1>Hello, world!</h1> 5 01234 5 sync 6 5 0`,
ssrHtml: `<h1>Hello, world!</h1> 5 01234 5 sync 6 5 0 10`,
async test({ assert, target }) {
await tick();
assert.htmlEqual(target.innerHTML, `<h1>Hello, world!</h1> 5 01234 5 sync 6 5 0`);
assert.htmlEqual(target.innerHTML, `<h1>Hello, world!</h1> 5 01234 5 sync 6 5 0 10`);
}
});

@ -23,4 +23,9 @@
{@render greet()}
{number} {sync} {after_async} {length} {first}
{#if sync}
{@const double = number * 2}
{double}
{/if}
</svelte:boundary>

Loading…
Cancel
Save