From 249faa55880accbc851877512fa698115e516ae7 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 25 Oct 2025 10:30:12 -0400 Subject: [PATCH] WIP --- .../src/compiler/phases/2-analyze/index.js | 4 +-- .../phases/2-analyze/visitors/IfBlock.js | 19 ---------- .../3-transform/client/visitors/IfBlock.js | 22 ++++++------ .../3-transform/client/visitors/Program.js | 27 +++++++++----- .../svelte/src/compiler/phases/types.d.ts | 20 ++++------- .../svelte/src/compiler/types/template.d.ts | 3 -- .../src/internal/client/dom/blocks/async.js | 6 ++-- .../src/internal/client/reactivity/async.js | 36 +++++++++++++------ .../src/internal/client/reactivity/effects.js | 5 +-- 9 files changed, 70 insertions(+), 72 deletions(-) diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js index 1c92d6f0da..fa10cc6ec0 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/index.js +++ b/packages/svelte/src/compiler/phases/2-analyze/index.js @@ -555,8 +555,8 @@ export function analyze_component(root, source, options) { snippets: new Set(), async_deriveds: new Set(), pickled_awaits: new Set(), - awaited_declarations: new Map(), - awaited_statements: new Map() + awaited_statements: new Map(), + promise_indexes: new Map() }; if (!runes) { diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/IfBlock.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/IfBlock.js index 8471b4d99b..dcdae3587f 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/IfBlock.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/IfBlock.js @@ -22,25 +22,6 @@ export function IfBlock(node, context) { expression: node.metadata.expression }); - // TODO this can be helperised - for (const binding of node.metadata.expression.dependencies) { - const awaited = context.state.analysis.awaited_declarations.get(binding.node.name); - - if (awaited) { - node.metadata.async ??= { - declarations: new Set() - }; - - node.metadata.async.declarations.add(awaited); - } - } - - if (node.metadata.expression.has_await) { - node.metadata.async ??= { - declarations: new Set() - }; - } - context.visit(node.consequent); if (node.alternate) context.visit(node.alternate); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/IfBlock.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/IfBlock.js index f96879029c..007f63bbb2 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/IfBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/IfBlock.js @@ -25,8 +25,16 @@ export function IfBlock(node, context) { statements.push(b.var(alternate_id, b.arrow([b.id('$$anchor')], alternate))); } + // TODO helperise + const promise_index = Array.from(node.metadata.expression.dependencies).reduce( + (index, binding) => Math.max(index, context.state.analysis.promise_indexes.get(binding) ?? -1), + -1 + ); + + const is_async = promise_index > -1 || node.metadata.expression.has_await; + const expression = build_expression(context, node.test, node.metadata.expression); - const test = node.metadata.async ? b.call('$.get', b.id('$$condition')) : expression; + const test = is_async ? b.call('$.get', b.id('$$condition')) : expression; /** @type {Expression[]} */ const args = [ @@ -70,20 +78,14 @@ export function IfBlock(node, context) { statements.push(add_svelte_meta(b.call('$.if', ...args), node, 'if')); - if (node.metadata.async) { + if (is_async) { context.state.init.push( b.stmt( b.call( '$.async', context.state.node, - b.array([...node.metadata.async.declarations].map((d) => d.id)), - b.array([ - b.arrow( - [...node.metadata.async.declarations].map((d) => d.pattern), - expression, - node.metadata.expression.has_await - ) - ]), + promise_index === -1 ? undefined : b.id(`$$promises[${promise_index}]`), + b.array([b.thunk(expression, node.metadata.expression.has_await)]), b.arrow([context.state.node, b.id('$$condition')], b.block(statements)) ) ) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js index 269b353523..6db73808e4 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Program.js @@ -166,7 +166,7 @@ function transform_body(program, context) { /** @type {AwaitedStatement[]} */ const deriveds = []; - const { awaited_statements } = context.state.analysis; + const { awaited_statements, promise_indexes } = context.state.analysis; let awaited = false; @@ -188,14 +188,17 @@ function transform_body(program, context) { return; } - if (node.type === 'VariableDeclarator') { - const rune = get_rune(node.init, context.state.scope); + // TODO put deriveds into a separate array, and group them immediately + // after their latest dependency. for now, to avoid having to figure + // out the intricacies of dependency tracking, just let 'em waterfall + // if (node.type === 'VariableDeclarator') { + // const rune = get_rune(node.init, context.state.scope); - if (rune === '$derived' || rune === '$derived.by') { - deriveds.push(statement); - return; - } - } + // if (rune === '$derived' || rune === '$derived.by') { + // deriveds.push(statement); + // return; + // } + // } statements.push(statement); }; @@ -306,5 +309,13 @@ function transform_body(program, context) { // console.log('statements', statements); // console.log('deriveds', deriveds); + for (let i = 0; i < statements.length; i += 1) { + const s = statements[i]; + + for (const binding of s.declarations) { + promise_indexes.set(binding, i); + } + } + return out; } diff --git a/packages/svelte/src/compiler/phases/types.d.ts b/packages/svelte/src/compiler/phases/types.d.ts index 8d2d526559..efec50cafb 100644 --- a/packages/svelte/src/compiler/phases/types.d.ts +++ b/packages/svelte/src/compiler/phases/types.d.ts @@ -129,23 +129,15 @@ export interface ComponentAnalysis extends Analysis { * Every snippet that is declared locally */ snippets: Set; - /** - * A lookup of awaited declarations. If you have something this in `