From de84f6bea0daebc71a515df510301520d992fdfe Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Thu, 28 Aug 2025 17:58:15 -0700 Subject: [PATCH 01/37] init --- .changeset/spicy-hotels-applaud.md | 5 ++ .../3-transform/client/transform-client.js | 9 ++- .../phases/3-transform/client/types.d.ts | 14 +++- .../phases/3-transform/client/utils.js | 59 ++++++++++++++++- .../3-transform/client/visitors/Program.js | 21 +++++- .../client/visitors/VariableDeclaration.js | 66 ++++++++++++++++--- packages/svelte/src/internal/client/index.js | 1 + .../src/internal/client/reactivity/async.js | 9 +++ 8 files changed, 166 insertions(+), 18 deletions(-) create mode 100644 .changeset/spicy-hotels-applaud.md diff --git a/.changeset/spicy-hotels-applaud.md b/.changeset/spicy-hotels-applaud.md new file mode 100644 index 0000000000..343a8baf4e --- /dev/null +++ b/.changeset/spicy-hotels-applaud.md @@ -0,0 +1,5 @@ +--- +'svelte': minor +--- + +feat: parallelize more async work diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index 940d6a9e00..54a984edd3 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -63,7 +63,7 @@ import { VariableDeclaration } from './visitors/VariableDeclaration.js'; /** @type {Visitors} */ const visitors = { - _: function set_scope(node, { next, state }) { + _: function set_scope(node, { path, next, state }) { const scope = state.scopes.get(node); if (scope && scope !== state.scope) { @@ -84,6 +84,9 @@ const visitors = { } else { next(); } + if (node.type !== 'VariableDeclaration' && path.at(-1)?.type === 'Program' && state.analysis.instance) { + state.current_parallelized_chunk = null; + } }, AnimateDirective, ArrowFunctionExpression, @@ -176,7 +179,9 @@ export function client_component(analysis, options) { update: /** @type {any} */ (null), after_update: /** @type {any} */ (null), template: /** @type {any} */ (null), - memoizer: /** @type {any} */ (null) + memoizer: /** @type {any} */ (null), + parallelized_derived_chunks: [], + current_parallelized_chunk: null }; const module = /** @type {ESTree.Program} */ ( diff --git a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts index 59c024dfb7..4e95ee05b9 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts @@ -7,7 +7,7 @@ import type { AssignmentExpression, UpdateExpression, VariableDeclaration, - Declaration + Pattern } from 'estree'; import type { AST, Namespace, ValidatedCompileOptions } from '#compiler'; import type { TransformState } from '../types.js'; @@ -83,6 +83,18 @@ export interface ComponentClientTransformState extends ClientTransformState { readonly instance_level_snippets: VariableDeclaration[]; /** Snippets hoisted to the module */ readonly module_level_snippets: VariableDeclaration[]; + readonly parallelized_derived_chunks: ParallelizedChunk[]; + current_parallelized_chunk: ParallelizedChunk | null; +} + +export interface ParallelizedChunk { + declarators: Array<{ + id: Pattern; + init: Expression; + }>; + kind: VariableDeclaration['kind']; + /** index in instance body */ + position: number; } export type Context = import('zimmerframe').Context; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index 19a4342b5e..45bd55f1f4 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -1,7 +1,7 @@ -/** @import { ArrowFunctionExpression, AssignmentExpression, BlockStatement, Expression, FunctionDeclaration, FunctionExpression, Identifier, Node, Pattern, UpdateExpression } from 'estree' */ +/** @import { ArrowFunctionExpression, AssignmentExpression, BlockStatement, CallExpression, Expression, FunctionDeclaration, FunctionExpression, Identifier, Node, Pattern, UpdateExpression } from 'estree' */ /** @import { Binding } from '#compiler' */ /** @import { ClientTransformState, ComponentClientTransformState, ComponentContext } from './types.js' */ -/** @import { Analysis } from '../../types.js' */ +/** @import { Analysis, ComponentAnalysis } from '../../types.js' */ /** @import { Scope } from '../../scope.js' */ import * as b from '#compiler/builders'; import { is_simple_expression } from '../../../utils/ast.js'; @@ -15,6 +15,7 @@ import { import { dev } from '../../../state.js'; import { walk } from 'zimmerframe'; import { validate_mutation } from './visitors/shared/utils.js'; +import is_reference from 'is-reference'; /** * @param {Binding} binding @@ -28,6 +29,60 @@ export function is_state_source(binding, analysis) { ); } +/** + * @param {Expression} expression + * @param {Scope} scope + * @param {Analysis | ComponentAnalysis} analysis + * @returns {boolean} + */ +export function can_be_parallelized(expression, scope, analysis) { + let has_closures = false; + /** @type {Set} */ + const references = new Set(); + walk(expression, null, { + ArrowFunctionExpression(_, { stop }) { + has_closures = true; + stop(); + }, + FunctionExpression(_, { stop }) { + has_closures = true; + stop(); + }, + Identifier(node, { path }) { + if (is_reference(node, /** @type {Node} */ (path.at(-1)))) { + references.add(node.name); + } + } + }); + if (has_closures) { + return false; + } + for (const reference of references) { + const binding = scope.get(reference); + if (!binding || binding.declaration_kind === 'import') { + return false; + } + if ('template' in analysis) { + if (binding.scope !== analysis.instance.scope) { + return false; + } + } else if (binding.scope !== analysis.module.scope) { + return false; + } + + if (binding.kind === 'derived') { + const init = /** @type {CallExpression} */ (binding.initial); + if (analysis.async_deriveds.has(init)) { + return false; + } + } + if (!binding.mutated && !binding.reassigned) { + continue; + } + } + return true; +} + /** * @param {Identifier} node * @param {ClientTransformState} state 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 07342da314..65532d42ec 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 @@ -5,10 +5,10 @@ import * as b from '#compiler/builders'; import { add_state_transformers } from './shared/declarations.js'; /** - * @param {Program} _ + * @param {Program} node * @param {ComponentContext} context */ -export function Program(_, context) { +export function Program(node, context) { if (!context.state.analysis.runes) { context.state.transform['$$props'] = { read: (node) => ({ ...node, name: '$$sanitized_props' }) @@ -137,5 +137,20 @@ export function Program(_, context) { add_state_transformers(context); - context.next(); + /** @type {Program['body']} */ + const body = []; + for (let i = 0; i < node.body.length; i++) { + const transformed = /** @type {Program['body'][number]} */ (context.visit(node.body[i])); + const chunk = context.state.parallelized_derived_chunks?.at(-1); + body.push(transformed); + if (chunk && chunk.position === i) { + const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); + const init = b.call('$.all', b.array(chunk.declarators.map(({ init }) => init))); + body.push(b.declaration(chunk.kind, [b.declarator(pattern, b.await(init))])); + } + } + return { + ...node, + body + }; } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 0998dc4778..247ddfcf58 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -1,12 +1,18 @@ -/** @import { CallExpression, Expression, Identifier, Literal, VariableDeclaration, VariableDeclarator } from 'estree' */ +/** @import { CallExpression, Expression, Identifier, Literal, Program, VariableDeclaration, VariableDeclarator } from 'estree' */ /** @import { Binding } from '#compiler' */ -/** @import { ComponentContext } from '../types' */ +/** @import { ComponentContext, ParallelizedChunk } from '../types' */ import { dev, is_ignored, locate_node } from '../../../../state.js'; import { extract_paths } from '../../../../utils/ast.js'; import * as b from '#compiler/builders'; import * as assert from '../../../../utils/assert.js'; import { get_rune } from '../../../scope.js'; -import { get_prop_source, is_prop_source, is_state_source, should_proxy } from '../utils.js'; +import { + can_be_parallelized, + get_prop_source, + is_prop_source, + is_state_source, + should_proxy +} from '../utils.js'; import { is_hoisted_function } from '../../utils.js'; import { get_value } from './shared/declarations.js'; @@ -200,6 +206,18 @@ export function VariableDeclaration(node, context) { const is_async = context.state.analysis.async_deriveds.has( /** @type {CallExpression} */ (init) ); + let parallelize = false; + if ( + is_async && + context.state.analysis.instance && + context.state.scope === context.state.analysis.instance.scope && + !dev + ) { + parallelize = can_be_parallelized(value, context.state.scope, context.state.analysis); + } + + /** @type {VariableDeclarator[]} */ + const derived_declarators = []; if (declarator.id.type === 'Identifier') { let expression = /** @type {Expression} */ ( @@ -212,7 +230,7 @@ export function VariableDeclaration(node, context) { if (is_async) { const location = dev && !is_ignored(init, 'await_waterfall') && locate_node(init); let call = b.call( - '$.async_derived', + '$.async_derived' + (parallelize ? '_p' : ''), b.thunk(expression, true), location ? b.literal(location) : undefined ); @@ -220,14 +238,14 @@ export function VariableDeclaration(node, context) { call = b.call(b.await(b.call('$.save', call))); if (dev) call = b.call('$.tag', call, b.literal(declarator.id.name)); - declarations.push(b.declarator(declarator.id, call)); + derived_declarators.push(b.declarator(declarator.id, call)); } else { if (rune === '$derived') expression = b.thunk(expression); let call = b.call('$.derived', expression); if (dev) call = b.call('$.tag', call, b.literal(declarator.id.name)); - declarations.push(b.declarator(declarator.id, call)); + derived_declarators.push(b.declarator(declarator.id, call)); } } else { const init = /** @type {CallExpression} */ (declarator.init); @@ -253,7 +271,9 @@ export function VariableDeclaration(node, context) { b.thunk(expression, true), location ? b.literal(location) : undefined ); - call = b.call(b.await(b.call('$.save', call))); + if (!parallelize) { + call = b.call(b.await(b.call('$.save', call))); + } } if (dev) { @@ -261,7 +281,7 @@ export function VariableDeclaration(node, context) { call = b.call('$.tag', call, b.literal(label)); } - declarations.push(b.declarator(id, call)); + derived_declarators.push(b.declarator(id, call)); } const { inserts, paths } = extract_paths(declarator.id, rhs); @@ -278,13 +298,13 @@ export function VariableDeclaration(node, context) { call = b.call('$.tag', call, b.literal(label)); } - declarations.push(b.declarator(id, call)); + derived_declarators.push(b.declarator(id, call)); } for (const path of paths) { const expression = /** @type {Expression} */ (context.visit(path.expression)); const call = b.call('$.derived', b.thunk(expression)); - declarations.push( + derived_declarators.push( b.declarator( path.node, dev @@ -295,6 +315,32 @@ export function VariableDeclaration(node, context) { } } + if (!parallelize) { + declarations.push(...derived_declarators); + } else if (derived_declarators.length > 0) { + /** @type {ParallelizedChunk['declarators']} */ + const declarators = derived_declarators.map(({ id, init }) => ({ + id, + init: /** @type {Expression} */ (init) + })); + if ( + context.state.current_parallelized_chunk && + context.state.current_parallelized_chunk.kind === node.kind && + context.state.current_parallelized_chunk.position === + /** @type {Program} */ (context.path.at(-1)).body.indexOf(node) + ) { + context.state.current_parallelized_chunk.declarators.push(...declarators); + } else { + const chunk = { + kind: node.kind, + declarators, + position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node) + }; + context.state.current_parallelized_chunk = chunk; + context.state.parallelized_derived_chunks.push(chunk); + } + } + continue; } } diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index c5b7bb845c..c88114de01 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -99,6 +99,7 @@ export { with_script } from './dom/template.js'; export { + all, async_body, for_await_track_reactivity_loss, save, diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js index 1ea1bbe561..0767bd3688 100644 --- a/packages/svelte/src/internal/client/reactivity/async.js +++ b/packages/svelte/src/internal/client/reactivity/async.js @@ -189,3 +189,12 @@ export async function async_body(fn) { unsuspend(); } } + +/** + * @template T + * @param {Array>} promises + * @returns {Promise>} + */ +export function all(...promises) { + return Promise.all(promises.map((promise) => save(promise).then((restore) => restore()))); +} From 0bbc880535fdab961160976350d844630da2992b Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:03:36 -0700 Subject: [PATCH 02/37] remove temporary test thing --- .../phases/3-transform/client/visitors/VariableDeclaration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 247ddfcf58..1166faad27 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -230,7 +230,7 @@ export function VariableDeclaration(node, context) { if (is_async) { const location = dev && !is_ignored(init, 'await_waterfall') && locate_node(init); let call = b.call( - '$.async_derived' + (parallelize ? '_p' : ''), + '$.async_derived', b.thunk(expression, true), location ? b.literal(location) : undefined ); From aafa27f5a3570784a0ff98c911137484901d555e Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:06:59 -0700 Subject: [PATCH 03/37] don't parallelize if only one derived can be parallelized --- .../phases/3-transform/client/visitors/Program.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) 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 65532d42ec..3146c6ef03 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 @@ -144,9 +144,18 @@ export function Program(node, context) { const chunk = context.state.parallelized_derived_chunks?.at(-1); body.push(transformed); if (chunk && chunk.position === i) { - const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); - const init = b.call('$.all', b.array(chunk.declarators.map(({ init }) => init))); - body.push(b.declaration(chunk.kind, [b.declarator(pattern, b.await(init))])); + if (chunk.declarators.length === 1) { + const declarator = chunk.declarators[0]; + body.push( + b.declaration(chunk.kind, [ + b.declarator(declarator.id, b.call(b.await(b.call('$.save', declarator.init)))) + ]) + ); + } else { + const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); + const init = b.call('$.all', b.array(chunk.declarators.map(({ init }) => init))); + body.push(b.declaration(chunk.kind, [b.declarator(pattern, b.await(init))])); + } } } return { From 2f7319c475a2f0467ca9ce6524bfe46e1f5df371 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:08:50 -0700 Subject: [PATCH 04/37] fix --- .../phases/3-transform/client/visitors/VariableDeclaration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 1166faad27..d2fbbcde98 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -235,7 +235,7 @@ export function VariableDeclaration(node, context) { location ? b.literal(location) : undefined ); - call = b.call(b.await(b.call('$.save', call))); + if (!parallelize) call = b.call(b.await(b.call('$.save', call))); if (dev) call = b.call('$.tag', call, b.literal(declarator.id.name)); derived_declarators.push(b.declarator(declarator.id, call)); From c0723add3993b306bc8061c80a25b1aa3cf1e4a9 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:11:56 -0700 Subject: [PATCH 05/37] fix? --- packages/svelte/src/internal/client/reactivity/async.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js index 0767bd3688..181c33e9b9 100644 --- a/packages/svelte/src/internal/client/reactivity/async.js +++ b/packages/svelte/src/internal/client/reactivity/async.js @@ -196,5 +196,9 @@ export async function async_body(fn) { * @returns {Promise>} */ export function all(...promises) { - return Promise.all(promises.map((promise) => save(promise).then((restore) => restore()))); + return Promise.all( + promises.map((promise) => + promise instanceof Promise ? save(promise).then((restore) => restore()) : promise + ) + ); } From aeff5f30621a8b1160c906826461bcdcd21e1445 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:12:48 -0700 Subject: [PATCH 06/37] lint --- .../compiler/phases/3-transform/client/transform-client.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index 54a984edd3..62396c60ed 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -84,7 +84,11 @@ const visitors = { } else { next(); } - if (node.type !== 'VariableDeclaration' && path.at(-1)?.type === 'Program' && state.analysis.instance) { + if ( + node.type !== 'VariableDeclaration' && + path.at(-1)?.type === 'Program' && + state.analysis.instance + ) { state.current_parallelized_chunk = null; } }, From 710d6a62824ca4192f6ec363510360a128078cc8 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:18:38 -0700 Subject: [PATCH 07/37] fix --- .../phases/3-transform/client/visitors/VariableDeclaration.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index d2fbbcde98..54641b14ac 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -211,7 +211,9 @@ export function VariableDeclaration(node, context) { is_async && context.state.analysis.instance && context.state.scope === context.state.analysis.instance.scope && - !dev + !dev && + // TODO make it work without this + declarator.id.type === 'Identifier' ) { parallelize = can_be_parallelized(value, context.state.scope, context.state.analysis); } From e07672b9f9041be1487c3083d8d4c49f7a29fe75 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 12:56:59 -0700 Subject: [PATCH 08/37] fix --- .../src/compiler/phases/3-transform/client/visitors/Program.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3146c6ef03..dab48188b6 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 @@ -153,7 +153,7 @@ export function Program(node, context) { ); } else { const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); - const init = b.call('$.all', b.array(chunk.declarators.map(({ init }) => init))); + const init = b.call('$.all', ...chunk.declarators.map(({ init }) => init)); body.push(b.declaration(chunk.kind, [b.declarator(pattern, b.await(init))])); } } From a5a5b8da891d0e787751e47fd2b01b61c5f79c51 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:08:18 -0700 Subject: [PATCH 09/37] tweak --- .../compiler/phases/3-transform/client/utils.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index 45bd55f1f4..6a51d3a736 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -37,6 +37,7 @@ export function is_state_source(binding, analysis) { */ export function can_be_parallelized(expression, scope, analysis) { let has_closures = false; + let should_stop = false; /** @type {Set} */ const references = new Set(); walk(expression, null, { @@ -52,9 +53,21 @@ export function can_be_parallelized(expression, scope, analysis) { if (is_reference(node, /** @type {Node} */ (path.at(-1)))) { references.add(node.name); } + }, + MemberExpression(node, { stop }) { + should_stop = true; + stop(); + }, + CallExpression(node, { stop }) { + should_stop = true; + stop(); + }, + NewExpression(node, { stop }) { + should_stop = true; + stop(); } }); - if (has_closures) { + if (has_closures || should_stop) { return false; } for (const reference of references) { From 76b47d7270d01aa37077f642be00b7f3021a1b09 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:30:31 -0700 Subject: [PATCH 10/37] more --- .../svelte/src/compiler/phases/3-transform/client/utils.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index 6a51d3a736..14352d855b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -65,6 +65,10 @@ export function can_be_parallelized(expression, scope, analysis) { NewExpression(node, { stop }) { should_stop = true; stop(); + }, + StaticBlock(node, { stop }) { + has_closures = true; + stop(); } }); if (has_closures || should_stop) { From f57ec19efbc2637769cf6079525d77542d02035e Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:32:09 -0700 Subject: [PATCH 11/37] doh --- packages/svelte/src/compiler/phases/3-transform/client/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index 14352d855b..ff1fdefbb1 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -40,7 +40,7 @@ export function can_be_parallelized(expression, scope, analysis) { let should_stop = false; /** @type {Set} */ const references = new Set(); - walk(expression, null, { + walk(/** @type {Node} */ (expression), null, { ArrowFunctionExpression(_, { stop }) { has_closures = true; stop(); From cd8969a9054cd65f2dfeecddd79b868e5724a681 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 17:30:27 -0700 Subject: [PATCH 12/37] try adding regular `await`ed variables --- .../3-transform/client/transform-client.js | 2 +- .../phases/3-transform/client/types.d.ts | 6 +- .../phases/3-transform/client/utils.js | 7 +- .../3-transform/client/visitors/Program.js | 2 +- .../client/visitors/VariableDeclaration.js | 80 +++++++++++++++---- 5 files changed, 76 insertions(+), 21 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index 62396c60ed..311de0901a 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -184,7 +184,7 @@ export function client_component(analysis, options) { after_update: /** @type {any} */ (null), template: /** @type {any} */ (null), memoizer: /** @type {any} */ (null), - parallelized_derived_chunks: [], + parallelized_chunks: [], current_parallelized_chunk: null }; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts index 4e95ee05b9..9a569f3a9f 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts @@ -9,7 +9,7 @@ import type { VariableDeclaration, Pattern } from 'estree'; -import type { AST, Namespace, ValidatedCompileOptions } from '#compiler'; +import type { AST, Binding, Namespace, ValidatedCompileOptions } from '#compiler'; import type { TransformState } from '../types.js'; import type { ComponentAnalysis } from '../../types.js'; import type { Template } from './transform-template/template.js'; @@ -83,7 +83,8 @@ export interface ComponentClientTransformState extends ClientTransformState { readonly instance_level_snippets: VariableDeclaration[]; /** Snippets hoisted to the module */ readonly module_level_snippets: VariableDeclaration[]; - readonly parallelized_derived_chunks: ParallelizedChunk[]; + /** async deriveds and certain awaited variables are chunked so they can be parallelized via `Promise.all` */ + readonly parallelized_chunks: ParallelizedChunk[]; current_parallelized_chunk: ParallelizedChunk | null; } @@ -95,6 +96,7 @@ export interface ParallelizedChunk { kind: VariableDeclaration['kind']; /** index in instance body */ position: number; + bindings: Binding[]; } export type Context = import('zimmerframe').Context; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index 45bd55f1f4..5a372e17bc 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -33,9 +33,10 @@ export function is_state_source(binding, analysis) { * @param {Expression} expression * @param {Scope} scope * @param {Analysis | ComponentAnalysis} analysis + * @param {Binding[]} bindings bindings currently being parallelized (and cannot be accessed) * @returns {boolean} */ -export function can_be_parallelized(expression, scope, analysis) { +export function can_be_parallelized(expression, scope, analysis, bindings) { let has_closures = false; /** @type {Set} */ const references = new Set(); @@ -70,6 +71,10 @@ export function can_be_parallelized(expression, scope, analysis) { return false; } + if (bindings.includes(binding)) { + return false; + } + if (binding.kind === 'derived') { const init = /** @type {CallExpression} */ (binding.initial); if (analysis.async_deriveds.has(init)) { 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 3146c6ef03..a4a1084da4 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 @@ -141,7 +141,7 @@ export function Program(node, context) { const body = []; for (let i = 0; i < node.body.length; i++) { const transformed = /** @type {Program['body'][number]} */ (context.visit(node.body[i])); - const chunk = context.state.parallelized_derived_chunks?.at(-1); + const chunk = context.state.parallelized_chunks?.at(-1); body.push(transformed); if (chunk && chunk.position === i) { if (chunk.declarators.length === 1) { diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 54641b14ac..8cf09c30ea 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -45,6 +45,52 @@ export function VariableDeclaration(node, context) { continue; } + if ( + init.type === 'AwaitExpression' && + context.state.analysis.instance?.scope === context.state.scope + ) { + const parallelize = can_be_parallelized( + init.argument, + context.state.scope, + context.state.analysis, + context.state.current_parallelized_chunk?.bindings ?? [] + ); + if (parallelize) { + const bindings = context.state.scope.get_bindings(declarator); + const visited = /** @type {VariableDeclarator} */ ( + context.visit({ + ...declarator, + init: init.argument + }) + ); + const declarators = [ + { + id: visited.id, + init: /** @type {Expression} */ (visited.init) + } + ]; + if ( + context.state.current_parallelized_chunk && + context.state.current_parallelized_chunk.kind === node.kind + ) { + context.state.current_parallelized_chunk.declarators.push(...declarators); + context.state.current_parallelized_chunk.bindings.push(...bindings); + context.state.current_parallelized_chunk.position = /** @type {Program} */ ( + context.path.at(-1) + ).body.indexOf(node); + } else { + const chunk = { + kind: node.kind, + declarators, + position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node), + bindings + }; + context.state.current_parallelized_chunk = chunk; + context.state.parallelized_chunks.push(chunk); + } + continue; + } + } declarations.push(/** @type {VariableDeclarator} */ (context.visit(declarator))); continue; } @@ -215,11 +261,18 @@ export function VariableDeclaration(node, context) { // TODO make it work without this declarator.id.type === 'Identifier' ) { - parallelize = can_be_parallelized(value, context.state.scope, context.state.analysis); + parallelize = can_be_parallelized( + value, + context.state.scope, + context.state.analysis, + context.state.current_parallelized_chunk?.bindings ?? [] + ); } /** @type {VariableDeclarator[]} */ const derived_declarators = []; + /** @type {Binding[]} */ + const bindings = []; if (declarator.id.type === 'Identifier') { let expression = /** @type {Expression} */ ( @@ -239,15 +292,13 @@ export function VariableDeclaration(node, context) { if (!parallelize) call = b.call(b.await(b.call('$.save', call))); if (dev) call = b.call('$.tag', call, b.literal(declarator.id.name)); - + bindings.push(/** @type {Binding} */ (context.state.scope.get(declarator.id.name))); derived_declarators.push(b.declarator(declarator.id, call)); } else { if (rune === '$derived') expression = b.thunk(expression); let call = b.call('$.derived', expression); if (dev) call = b.call('$.tag', call, b.literal(declarator.id.name)); - - derived_declarators.push(b.declarator(declarator.id, call)); } } else { const init = /** @type {CallExpression} */ (declarator.init); @@ -273,17 +324,13 @@ export function VariableDeclaration(node, context) { b.thunk(expression, true), location ? b.literal(location) : undefined ); - if (!parallelize) { - call = b.call(b.await(b.call('$.save', call))); - } + call = b.call(b.await(b.call('$.save', call))); } if (dev) { const label = `[$derived ${declarator.id.type === 'ArrayPattern' ? 'iterable' : 'object'}]`; call = b.call('$.tag', call, b.literal(label)); } - - derived_declarators.push(b.declarator(id, call)); } const { inserts, paths } = extract_paths(declarator.id, rhs); @@ -299,8 +346,6 @@ export function VariableDeclaration(node, context) { const label = `[$derived ${declarator.id.type === 'ArrayPattern' ? 'iterable' : 'object'}]`; call = b.call('$.tag', call, b.literal(label)); } - - derived_declarators.push(b.declarator(id, call)); } for (const path of paths) { @@ -327,19 +372,22 @@ export function VariableDeclaration(node, context) { })); if ( context.state.current_parallelized_chunk && - context.state.current_parallelized_chunk.kind === node.kind && - context.state.current_parallelized_chunk.position === - /** @type {Program} */ (context.path.at(-1)).body.indexOf(node) + context.state.current_parallelized_chunk.kind === node.kind ) { context.state.current_parallelized_chunk.declarators.push(...declarators); + context.state.current_parallelized_chunk.bindings.push(...bindings); + context.state.current_parallelized_chunk.position = /** @type {Program} */ ( + context.path.at(-1) + ).body.indexOf(node); } else { const chunk = { kind: node.kind, declarators, - position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node) + position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node), + bindings }; context.state.current_parallelized_chunk = chunk; - context.state.parallelized_derived_chunks.push(chunk); + context.state.parallelized_chunks.push(chunk); } } From 1b55045a162f590801d547025d9b5231004a6c32 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 17:32:32 -0700 Subject: [PATCH 13/37] doh --- .../phases/3-transform/client/visitors/VariableDeclaration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 8cf09c30ea..c8e258e19b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -46,7 +46,7 @@ export function VariableDeclaration(node, context) { continue; } if ( - init.type === 'AwaitExpression' && + init?.type === 'AwaitExpression' && context.state.analysis.instance?.scope === context.state.scope ) { const parallelize = can_be_parallelized( From 8091a6eb367b36ca0db74a2e1fa29cc799d1159e Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 17:35:43 -0700 Subject: [PATCH 14/37] more --- .../3-transform/client/visitors/VariableDeclaration.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index c8e258e19b..878a6e89c9 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -261,12 +261,10 @@ export function VariableDeclaration(node, context) { // TODO make it work without this declarator.id.type === 'Identifier' ) { - parallelize = can_be_parallelized( - value, - context.state.scope, - context.state.analysis, - context.state.current_parallelized_chunk?.bindings ?? [] - ); + parallelize = can_be_parallelized(value, context.state.scope, context.state.analysis, [ + ...(context.state.current_parallelized_chunk?.bindings ?? []), + ...context.state.scope.get_bindings(declarator) + ]); } /** @type {VariableDeclarator[]} */ From f5972d323790c26823b8cdefd033b75ac0e9a509 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 17:39:08 -0700 Subject: [PATCH 15/37] fix --- .../phases/3-transform/client/visitors/VariableDeclaration.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 878a6e89c9..6b49abfd96 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -297,6 +297,7 @@ export function VariableDeclaration(node, context) { let call = b.call('$.derived', expression); if (dev) call = b.call('$.tag', call, b.literal(declarator.id.name)); + derived_declarators.push(b.declarator(declarator.id, call)); } } else { const init = /** @type {CallExpression} */ (declarator.init); @@ -329,6 +330,7 @@ export function VariableDeclaration(node, context) { const label = `[$derived ${declarator.id.type === 'ArrayPattern' ? 'iterable' : 'object'}]`; call = b.call('$.tag', call, b.literal(label)); } + derived_declarators.push(b.declarator(id, call)); } const { inserts, paths } = extract_paths(declarator.id, rhs); From fc03ba7e1b4b1a5464ea390ec9c3f39c27907121 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 17:41:44 -0700 Subject: [PATCH 16/37] more --- .../phases/3-transform/client/visitors/VariableDeclaration.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 6b49abfd96..db7e909164 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -346,6 +346,7 @@ export function VariableDeclaration(node, context) { const label = `[$derived ${declarator.id.type === 'ArrayPattern' ? 'iterable' : 'object'}]`; call = b.call('$.tag', call, b.literal(label)); } + derived_declarators.push(b.declarator(id, call)); } for (const path of paths) { From ccc993933cdcf95208e4d43cb5f4057fb6892d5e Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 18:02:07 -0700 Subject: [PATCH 17/37] fix --- .../3-transform/client/visitors/Program.js | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) 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 1e9789e9d5..c2febd3e7b 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 @@ -141,22 +141,29 @@ export function Program(node, context) { const body = []; for (let i = 0; i < node.body.length; i++) { const transformed = /** @type {Program['body'][number]} */ (context.visit(node.body[i])); - const chunk = context.state.parallelized_chunks?.at(-1); body.push(transformed); - if (chunk && chunk.position === i) { - if (chunk.declarators.length === 1) { - const declarator = chunk.declarators[0]; - body.push( - b.declaration(chunk.kind, [ - b.declarator(declarator.id, b.call(b.await(b.call('$.save', declarator.init)))) - ]) - ); - } else { - const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); - const init = b.call('$.all', ...chunk.declarators.map(({ init }) => init)); - body.push(b.declaration(chunk.kind, [b.declarator(pattern, b.await(init))])); - } + } + let offset = 0; + for (const chunk of context.state.parallelized_chunks) { + if (chunk.declarators.length === 1) { + const declarator = chunk.declarators[0]; + body.splice( + chunk.position + offset, + 0, + b.declaration(chunk.kind, [ + b.declarator(declarator.id, b.call(b.await(b.call('$.save', declarator.init)))) + ]) + ); + } else { + const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); + const init = b.call('$.all', ...chunk.declarators.map(({ init }) => init)); + body.splice( + chunk.position + offset, + 0, + b.declaration(chunk.kind, [b.declarator(pattern, b.await(init))]) + ); } + offset++; } return { ...node, From 9ab08aaf1511d00a617d49586ce3f69188fa1e5d Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 18:06:12 -0700 Subject: [PATCH 18/37] fix --- .../3-transform/client/visitors/Program.js | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) 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 c2febd3e7b..72bb7828e0 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 @@ -143,27 +143,29 @@ export function Program(node, context) { const transformed = /** @type {Program['body'][number]} */ (context.visit(node.body[i])); body.push(transformed); } - let offset = 0; - for (const chunk of context.state.parallelized_chunks) { - if (chunk.declarators.length === 1) { - const declarator = chunk.declarators[0]; - body.splice( - chunk.position + offset, - 0, - b.declaration(chunk.kind, [ - b.declarator(declarator.id, b.call(b.await(b.call('$.save', declarator.init)))) - ]) - ); - } else { - const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); - const init = b.call('$.all', ...chunk.declarators.map(({ init }) => init)); - body.splice( - chunk.position + offset, - 0, - b.declaration(chunk.kind, [b.declarator(pattern, b.await(init))]) - ); + if (context.state.parallelized_chunks) { + let offset = 0; + for (const chunk of context.state.parallelized_chunks) { + if (chunk.declarators.length === 1) { + const declarator = chunk.declarators[0]; + body.splice( + chunk.position + offset, + 0, + b.declaration(chunk.kind, [ + b.declarator(declarator.id, b.call(b.await(b.call('$.save', declarator.init)))) + ]) + ); + } else { + const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); + const init = b.call('$.all', ...chunk.declarators.map(({ init }) => init)); + body.splice( + chunk.position + offset, + 0, + b.declaration(chunk.kind, [b.declarator(pattern, b.await(init))]) + ); + } + offset++; } - offset++; } return { ...node, From 1c2ea7541606e7fbea86cbdc31cb3ce836f83c30 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 18:26:48 -0700 Subject: [PATCH 19/37] make it work in dev --- .../phases/3-transform/client/types.d.ts | 1 + .../3-transform/client/visitors/Program.js | 9 +++++-- .../client/visitors/VariableDeclaration.js | 24 ++++++++++++++----- .../svelte/src/internal/client/dev/tracing.js | 11 +++++++++ packages/svelte/src/internal/client/index.js | 3 ++- .../src/internal/client/reactivity/async.js | 2 ++ 6 files changed, 41 insertions(+), 9 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts index 9a569f3a9f..e67b14e624 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts @@ -97,6 +97,7 @@ export interface ParallelizedChunk { /** index in instance body */ position: number; bindings: Binding[]; + type: 'promise_all' | 'all'; } export type Context = import('zimmerframe').Context; 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 72bb7828e0..12a8f71c6c 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 @@ -152,12 +152,17 @@ export function Program(node, context) { chunk.position + offset, 0, b.declaration(chunk.kind, [ - b.declarator(declarator.id, b.call(b.await(b.call('$.save', declarator.init)))) + b.declarator( + declarator.id, + chunk.type === 'promise_all' + ? b.await(declarator.init) + : b.call(b.await(b.call('$.save', declarator.init))) + ) ]) ); } else { const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); - const init = b.call('$.all', ...chunk.declarators.map(({ init }) => init)); + const init = b.call(`$.${chunk.type}`, ...chunk.declarators.map(({ init }) => init)); body.splice( chunk.position + offset, 0, diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index db7e909164..49f9e721f8 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -71,7 +71,8 @@ export function VariableDeclaration(node, context) { ]; if ( context.state.current_parallelized_chunk && - context.state.current_parallelized_chunk.kind === node.kind + context.state.current_parallelized_chunk.kind === node.kind && + context.state.current_parallelized_chunk.type === 'all' ) { context.state.current_parallelized_chunk.declarators.push(...declarators); context.state.current_parallelized_chunk.bindings.push(...bindings); @@ -79,11 +80,13 @@ export function VariableDeclaration(node, context) { context.path.at(-1) ).body.indexOf(node); } else { + /** @type {ParallelizedChunk} */ const chunk = { kind: node.kind, declarators, position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node), - bindings + bindings, + type: 'all' }; context.state.current_parallelized_chunk = chunk; context.state.parallelized_chunks.push(chunk); @@ -257,7 +260,6 @@ export function VariableDeclaration(node, context) { is_async && context.state.analysis.instance && context.state.scope === context.state.analysis.instance.scope && - !dev && // TODO make it work without this declarator.id.type === 'Identifier' ) { @@ -266,6 +268,7 @@ export function VariableDeclaration(node, context) { ...context.state.scope.get_bindings(declarator) ]); } + const type = parallelize ? (dev ? 'promise_all' : 'all') : null; /** @type {VariableDeclarator[]} */ const derived_declarators = []; @@ -289,7 +292,13 @@ export function VariableDeclaration(node, context) { ); if (!parallelize) call = b.call(b.await(b.call('$.save', call))); - if (dev) call = b.call('$.tag', call, b.literal(declarator.id.name)); + if (dev) { + call = b.call( + '$.tag' + (parallelize ? '_async' : ''), + call, + b.literal(declarator.id.name) + ); + } bindings.push(/** @type {Binding} */ (context.state.scope.get(declarator.id.name))); derived_declarators.push(b.declarator(declarator.id, call)); } else { @@ -373,7 +382,8 @@ export function VariableDeclaration(node, context) { })); if ( context.state.current_parallelized_chunk && - context.state.current_parallelized_chunk.kind === node.kind + context.state.current_parallelized_chunk.kind === node.kind && + context.state.current_parallelized_chunk.type === type ) { context.state.current_parallelized_chunk.declarators.push(...declarators); context.state.current_parallelized_chunk.bindings.push(...bindings); @@ -381,11 +391,13 @@ export function VariableDeclaration(node, context) { context.path.at(-1) ).body.indexOf(node); } else { + /** @type {ParallelizedChunk} */ const chunk = { kind: node.kind, declarators, position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node), - bindings + bindings, + type: /** @type {ParallelizedChunk['type']} */ (type) }; context.state.current_parallelized_chunk = chunk; context.state.parallelized_chunks.push(chunk); diff --git a/packages/svelte/src/internal/client/dev/tracing.js b/packages/svelte/src/internal/client/dev/tracing.js index 673a710fac..f66e0a8106 100644 --- a/packages/svelte/src/internal/client/dev/tracing.js +++ b/packages/svelte/src/internal/client/dev/tracing.js @@ -184,6 +184,17 @@ export function tag(source, label) { return source; } +/** + * @template T + * @param {Promise>} promise + * @param {string} label + * @returns {Promise>} + */ +export async function tag_async(promise, label) { + const source = await promise; + return tag(source, label); +} + /** * @param {unknown} value * @param {string} label diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index c88114de01..9b45e264eb 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -7,7 +7,7 @@ export { add_locations } from './dev/elements.js'; export { hmr } from './dev/hmr.js'; export { create_ownership_validator } from './dev/ownership.js'; export { check_target, legacy_api } from './dev/legacy.js'; -export { trace, tag, tag_proxy } from './dev/tracing.js'; +export { trace, tag, tag_async, tag_proxy } from './dev/tracing.js'; export { inspect } from './dev/inspect.js'; export { async } from './dom/blocks/async.js'; export { validate_snippet_args } from './dev/validation.js'; @@ -102,6 +102,7 @@ export { all, async_body, for_await_track_reactivity_loss, + promise_all, save, track_reactivity_loss } from './reactivity/async.js'; diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js index 181c33e9b9..c0e081b017 100644 --- a/packages/svelte/src/internal/client/reactivity/async.js +++ b/packages/svelte/src/internal/client/reactivity/async.js @@ -202,3 +202,5 @@ export function all(...promises) { ) ); } + +export const promise_all = Promise.all; From c8cc9319be07c3474f312897935f096ad1cee130 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 18:31:49 -0700 Subject: [PATCH 20/37] try this --- .../phases/3-transform/client/visitors/VariableDeclaration.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 49f9e721f8..e6ed9b0b42 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -268,7 +268,8 @@ export function VariableDeclaration(node, context) { ...context.state.scope.get_bindings(declarator) ]); } - const type = parallelize ? (dev ? 'promise_all' : 'all') : null; + // const type = parallelize ? (dev ? 'promise_all' : 'all') : null; + const type = 'all'; /** @type {VariableDeclarator[]} */ const derived_declarators = []; From 464d7b6eabb967adad63c96c32a567e10a726232 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 18:40:38 -0700 Subject: [PATCH 21/37] remove unused --- .../compiler/phases/3-transform/client/types.d.ts | 1 - .../phases/3-transform/client/visitors/Program.js | 9 ++------- .../client/visitors/VariableDeclaration.js | 14 ++++---------- packages/svelte/src/internal/client/index.js | 1 - .../svelte/src/internal/client/reactivity/async.js | 2 -- 5 files changed, 6 insertions(+), 21 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts index e67b14e624..9a569f3a9f 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts @@ -97,7 +97,6 @@ export interface ParallelizedChunk { /** index in instance body */ position: number; bindings: Binding[]; - type: 'promise_all' | 'all'; } export type Context = import('zimmerframe').Context; 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 12a8f71c6c..b3f86c01d2 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 @@ -152,17 +152,12 @@ export function Program(node, context) { chunk.position + offset, 0, b.declaration(chunk.kind, [ - b.declarator( - declarator.id, - chunk.type === 'promise_all' - ? b.await(declarator.init) - : b.call(b.await(b.call('$.save', declarator.init))) - ) + b.declarator(declarator.id, b.call(b.await(b.call('$.save', declarator.init)))) ]) ); } else { const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); - const init = b.call(`$.${chunk.type}`, ...chunk.declarators.map(({ init }) => init)); + const init = b.call(`$.all`, ...chunk.declarators.map(({ init }) => init)); body.splice( chunk.position + offset, 0, diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index e6ed9b0b42..3e28b86639 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -71,8 +71,7 @@ export function VariableDeclaration(node, context) { ]; if ( context.state.current_parallelized_chunk && - context.state.current_parallelized_chunk.kind === node.kind && - context.state.current_parallelized_chunk.type === 'all' + context.state.current_parallelized_chunk.kind === node.kind ) { context.state.current_parallelized_chunk.declarators.push(...declarators); context.state.current_parallelized_chunk.bindings.push(...bindings); @@ -85,8 +84,7 @@ export function VariableDeclaration(node, context) { kind: node.kind, declarators, position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node), - bindings, - type: 'all' + bindings }; context.state.current_parallelized_chunk = chunk; context.state.parallelized_chunks.push(chunk); @@ -268,8 +266,6 @@ export function VariableDeclaration(node, context) { ...context.state.scope.get_bindings(declarator) ]); } - // const type = parallelize ? (dev ? 'promise_all' : 'all') : null; - const type = 'all'; /** @type {VariableDeclarator[]} */ const derived_declarators = []; @@ -383,8 +379,7 @@ export function VariableDeclaration(node, context) { })); if ( context.state.current_parallelized_chunk && - context.state.current_parallelized_chunk.kind === node.kind && - context.state.current_parallelized_chunk.type === type + context.state.current_parallelized_chunk.kind === node.kind ) { context.state.current_parallelized_chunk.declarators.push(...declarators); context.state.current_parallelized_chunk.bindings.push(...bindings); @@ -397,8 +392,7 @@ export function VariableDeclaration(node, context) { kind: node.kind, declarators, position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node), - bindings, - type: /** @type {ParallelizedChunk['type']} */ (type) + bindings }; context.state.current_parallelized_chunk = chunk; context.state.parallelized_chunks.push(chunk); diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index 9b45e264eb..04dd4cfb13 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -102,7 +102,6 @@ export { all, async_body, for_await_track_reactivity_loss, - promise_all, save, track_reactivity_loss } from './reactivity/async.js'; diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js index c0e081b017..181c33e9b9 100644 --- a/packages/svelte/src/internal/client/reactivity/async.js +++ b/packages/svelte/src/internal/client/reactivity/async.js @@ -202,5 +202,3 @@ export function all(...promises) { ) ); } - -export const promise_all = Promise.all; From 7788c30087db0959843755cfb417f21c4c87b841 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 20:27:15 -0700 Subject: [PATCH 22/37] try this --- .../phases/3-transform/client/visitors/Identifier.js | 7 +++++-- .../3-transform/client/visitors/VariableDeclaration.js | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Identifier.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Identifier.js index b01ed01bd7..3df8d24cba 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Identifier.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Identifier.js @@ -1,12 +1,12 @@ /** @import { Identifier, Node } from 'estree' */ -/** @import { Context } from '../types' */ +/** @import { ComponentContext } from '../types' */ import is_reference from 'is-reference'; import * as b from '#compiler/builders'; import { build_getter } from '../utils.js'; /** * @param {Identifier} node - * @param {Context} context + * @param {ComponentContext} context */ export function Identifier(node, context) { const parent = /** @type {Node} */ (context.path.at(-1)); @@ -35,6 +35,9 @@ export function Identifier(node, context) { return b.id('$$props'); } } + if (binding && context.state.current_parallelized_chunk?.bindings?.includes(binding)) { + context.state.current_parallelized_chunk = null; + } return build_getter(node, context.state); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 3e28b86639..00ba36d76e 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -53,7 +53,10 @@ export function VariableDeclaration(node, context) { init.argument, context.state.scope, context.state.analysis, - context.state.current_parallelized_chunk?.bindings ?? [] + [ + ...(context.state.current_parallelized_chunk?.bindings ?? []), + ...context.state.scope.get_bindings(declarator) + ] ); if (parallelize) { const bindings = context.state.scope.get_bindings(declarator); From c17a1e3ed2b2eb5181d93b4b59b9373f2b844af2 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 20:43:21 -0700 Subject: [PATCH 23/37] cleanup --- .../client/visitors/VariableDeclaration.js | 64 ++++++++----------- 1 file changed, 25 insertions(+), 39 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 00ba36d76e..2461c74dff 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -1,4 +1,4 @@ -/** @import { CallExpression, Expression, Identifier, Literal, Program, VariableDeclaration, VariableDeclarator } from 'estree' */ +/** @import { CallExpression, Expression, Identifier, Literal, Node, Program, VariableDeclaration, VariableDeclarator } from 'estree' */ /** @import { Binding } from '#compiler' */ /** @import { ComponentContext, ParallelizedChunk } from '../types' */ import { dev, is_ignored, locate_node } from '../../../../state.js'; @@ -23,12 +23,14 @@ import { get_value } from './shared/declarations.js'; export function VariableDeclaration(node, context) { /** @type {VariableDeclarator[]} */ const declarations = []; + const parent = /** @type {Node} */ (context.path.at(-1)); + const position = /** @type {Program} */ (parent).body?.indexOf?.(node); if (context.state.analysis.runes) { for (const declarator of node.declarations) { const init = /** @type {Expression} */ (declarator.init); const rune = get_rune(init, context.state.scope); - + const bindings = context.state.scope.get_bindings(declarator); if ( !rune || rune === '$effect.tracking' || @@ -53,40 +55,34 @@ export function VariableDeclaration(node, context) { init.argument, context.state.scope, context.state.analysis, - [ - ...(context.state.current_parallelized_chunk?.bindings ?? []), - ...context.state.scope.get_bindings(declarator) - ] + [...(context.state.current_parallelized_chunk?.bindings ?? []), ...bindings] ); if (parallelize) { - const bindings = context.state.scope.get_bindings(declarator); - const visited = /** @type {VariableDeclarator} */ ( + const { id, init: visited_init } = /** @type {VariableDeclarator} */ ( context.visit({ ...declarator, init: init.argument }) ); - const declarators = [ - { - id: visited.id, - init: /** @type {Expression} */ (visited.init) - } - ]; + const _declarator = { + id, + init: /** @type {Expression} */ (visited_init) + }; if ( context.state.current_parallelized_chunk && context.state.current_parallelized_chunk.kind === node.kind ) { - context.state.current_parallelized_chunk.declarators.push(...declarators); + context.state.current_parallelized_chunk.declarators.push(_declarator); context.state.current_parallelized_chunk.bindings.push(...bindings); context.state.current_parallelized_chunk.position = /** @type {Program} */ ( - context.path.at(-1) + parent ).body.indexOf(node); } else { /** @type {ParallelizedChunk} */ const chunk = { kind: node.kind, - declarators, - position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node), + declarators: [_declarator], + position, bindings }; context.state.current_parallelized_chunk = chunk; @@ -185,9 +181,7 @@ export function VariableDeclaration(node, context) { * @param {Expression} value */ const create_state_declarator = (id, value) => { - const binding = /** @type {import('#compiler').Binding} */ ( - context.state.scope.get(id.name) - ); + const binding = /** @type {Binding} */ (context.state.scope.get(id.name)); const is_state = is_state_source(binding, context.state.analysis); const is_proxy = should_proxy(value, context.state.scope); @@ -386,15 +380,13 @@ export function VariableDeclaration(node, context) { ) { context.state.current_parallelized_chunk.declarators.push(...declarators); context.state.current_parallelized_chunk.bindings.push(...bindings); - context.state.current_parallelized_chunk.position = /** @type {Program} */ ( - context.path.at(-1) - ).body.indexOf(node); + context.state.current_parallelized_chunk.position = position; } else { /** @type {ParallelizedChunk} */ const chunk = { kind: node.kind, declarators, - position: /** @type {Program} */ (context.path.at(-1)).body.indexOf(node), + position, bindings }; context.state.current_parallelized_chunk = chunk; @@ -407,7 +399,7 @@ export function VariableDeclaration(node, context) { } } else { for (const declarator of node.declarations) { - const bindings = /** @type {Binding[]} */ (context.state.scope.get_bindings(declarator)); + const bindings = context.state.scope.get_bindings(declarator); const has_state = bindings.some((binding) => binding.kind === 'state'); const has_props = bindings.some((binding) => binding.kind === 'bindable_prop'); @@ -510,13 +502,9 @@ export function VariableDeclaration(node, context) { * @param {Expression} value */ function create_state_declarators(declarator, context, value) { + const immutable = context.state.analysis.immutable ? b.true : undefined; if (declarator.id.type === 'Identifier') { - return [ - b.declarator( - declarator.id, - b.call('$.mutable_source', value, context.state.analysis.immutable ? b.true : undefined) - ) - ]; + return [b.declarator(declarator.id, b.call('$.mutable_source', value, immutable))]; } const tmp = b.id(context.state.scope.generate('tmp')); @@ -531,15 +519,13 @@ function create_state_declarators(declarator, context, value) { const expression = /** @type {Expression} */ (context.visit(b.thunk(value))); return b.declarator(id, b.call('$.derived', expression)); }), - ...paths.map((path) => { - const value = /** @type {Expression} */ (context.visit(path.expression)); - const binding = context.state.scope.get(/** @type {Identifier} */ (path.node).name); + ...paths.map(({ expression, node }) => { + const value = /** @type {Expression} */ (context.visit(expression)); + const binding = context.state.scope.get(/** @type {Identifier} */ (node).name); return b.declarator( - path.node, - binding?.kind === 'state' - ? b.call('$.mutable_source', value, context.state.analysis.immutable ? b.true : undefined) - : value + node, + binding?.kind === 'state' ? b.call('$.mutable_source', value, immutable) : value ); }) ]; From c41900c66623626e3f6d92afcdcbdbd8db1d9714 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Fri, 29 Aug 2025 20:55:19 -0700 Subject: [PATCH 24/37] more --- .../client/visitors/VariableDeclaration.js | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 2461c74dff..ad9f6993d9 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -51,11 +51,12 @@ export function VariableDeclaration(node, context) { init?.type === 'AwaitExpression' && context.state.analysis.instance?.scope === context.state.scope ) { + const current_chunk = context.state.current_parallelized_chunk; const parallelize = can_be_parallelized( init.argument, context.state.scope, context.state.analysis, - [...(context.state.current_parallelized_chunk?.bindings ?? []), ...bindings] + [...(current_chunk?.bindings ?? []), ...bindings] ); if (parallelize) { const { id, init: visited_init } = /** @type {VariableDeclarator} */ ( @@ -68,15 +69,10 @@ export function VariableDeclaration(node, context) { id, init: /** @type {Expression} */ (visited_init) }; - if ( - context.state.current_parallelized_chunk && - context.state.current_parallelized_chunk.kind === node.kind - ) { - context.state.current_parallelized_chunk.declarators.push(_declarator); - context.state.current_parallelized_chunk.bindings.push(...bindings); - context.state.current_parallelized_chunk.position = /** @type {Program} */ ( - parent - ).body.indexOf(node); + if (current_chunk && current_chunk.kind === node.kind) { + current_chunk.declarators.push(_declarator); + current_chunk.bindings.push(...bindings); + current_chunk.position = /** @type {Program} */ (parent).body.indexOf(node); } else { /** @type {ParallelizedChunk} */ const chunk = { @@ -251,6 +247,7 @@ export function VariableDeclaration(node, context) { /** @type {CallExpression} */ (init) ); let parallelize = false; + const current_chunk = context.state.current_parallelized_chunk; if ( is_async && context.state.analysis.instance && @@ -259,7 +256,7 @@ export function VariableDeclaration(node, context) { declarator.id.type === 'Identifier' ) { parallelize = can_be_parallelized(value, context.state.scope, context.state.analysis, [ - ...(context.state.current_parallelized_chunk?.bindings ?? []), + ...(current_chunk?.bindings ?? []), ...context.state.scope.get_bindings(declarator) ]); } @@ -369,18 +366,14 @@ export function VariableDeclaration(node, context) { if (!parallelize) { declarations.push(...derived_declarators); } else if (derived_declarators.length > 0) { - /** @type {ParallelizedChunk['declarators']} */ const declarators = derived_declarators.map(({ id, init }) => ({ id, init: /** @type {Expression} */ (init) })); - if ( - context.state.current_parallelized_chunk && - context.state.current_parallelized_chunk.kind === node.kind - ) { - context.state.current_parallelized_chunk.declarators.push(...declarators); - context.state.current_parallelized_chunk.bindings.push(...bindings); - context.state.current_parallelized_chunk.position = position; + if (current_chunk && current_chunk.kind === node.kind) { + current_chunk.declarators.push(...declarators); + current_chunk.bindings.push(...bindings); + current_chunk.position = position; } else { /** @type {ParallelizedChunk} */ const chunk = { From dad4889c51f9626c22cfaa8a2b904739dc72e641 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sat, 30 Aug 2025 17:10:41 -0700 Subject: [PATCH 25/37] this probably isn't necessary? --- .../compiler/phases/3-transform/client/transform-client.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index 311de0901a..f3510b42e1 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -84,13 +84,6 @@ const visitors = { } else { next(); } - if ( - node.type !== 'VariableDeclaration' && - path.at(-1)?.type === 'Program' && - state.analysis.instance - ) { - state.current_parallelized_chunk = null; - } }, AnimateDirective, ArrowFunctionExpression, From b138c6055b7814a87b94f3e88ad23097bfd2fbc7 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sat, 30 Aug 2025 17:11:42 -0700 Subject: [PATCH 26/37] remove unused param --- .../src/compiler/phases/3-transform/client/transform-client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index f3510b42e1..b7cfd30b7c 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -63,7 +63,7 @@ import { VariableDeclaration } from './visitors/VariableDeclaration.js'; /** @type {Visitors} */ const visitors = { - _: function set_scope(node, { path, next, state }) { + _: function set_scope(node, { next, state }) { const scope = state.scopes.get(node); if (scope && scope !== state.scope) { From 82cb5156c79f8648f0474fba8c29a6c40ea4a6ea Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sat, 30 Aug 2025 17:21:08 -0700 Subject: [PATCH 27/37] parallelize `await` expressions in instance --- .../phases/3-transform/client/types.d.ts | 4 +- .../client/visitors/ExpressionStatement.js | 40 ++++++++++++++++++- .../3-transform/client/visitors/Program.js | 26 +++++++----- .../client/visitors/VariableDeclaration.js | 9 ++++- 4 files changed, 64 insertions(+), 15 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts index 9a569f3a9f..46c922aa33 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts @@ -90,10 +90,10 @@ export interface ComponentClientTransformState extends ClientTransformState { export interface ParallelizedChunk { declarators: Array<{ - id: Pattern; + id: Pattern | null; init: Expression; }>; - kind: VariableDeclaration['kind']; + kind: VariableDeclaration['kind'] | null; /** index in instance body */ position: number; bindings: Binding[]; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js index 859842ebc3..75c003c0ad 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js @@ -1,13 +1,16 @@ -/** @import { Expression, ExpressionStatement } from 'estree' */ -/** @import { ComponentContext } from '../types' */ +/** @import { Expression, ExpressionStatement, Node, Program } from 'estree' */ +/** @import { ComponentContext, ParallelizedChunk } from '../types' */ import * as b from '#compiler/builders'; import { get_rune } from '../../../scope.js'; +import { can_be_parallelized } from '../utils.js'; /** * @param {ExpressionStatement} node * @param {ComponentContext} context */ export function ExpressionStatement(node, context) { + const parent = /** @type {Node} */ (context.path.at(-1)); + const position = /** @type {Program} */ (parent).body?.indexOf?.(node); if (node.expression.type === 'CallExpression') { const rune = get_rune(node.expression, context.state.scope); @@ -25,6 +28,39 @@ export function ExpressionStatement(node, context) { return b.empty; } } + if ( + node.expression.type === 'AwaitExpression' && + context.state.analysis.instance?.scope === context.state.scope + ) { + const current_chunk = context.state.current_parallelized_chunk; + const parallelize = can_be_parallelized( + node.expression.argument, + context.state.scope, + context.state.analysis, + current_chunk?.bindings ?? [] + ); + if (parallelize) { + const declarator = { + id: null, + init: /** @type {Expression} */ (context.visit(node.expression)) + }; + if (current_chunk) { + current_chunk.declarators.push(declarator); + current_chunk.position = position; + } else { + /** @type {ParallelizedChunk} */ + const chunk = { + kind: null, + declarators: [declarator], + position, + bindings: [] + }; + context.state.current_parallelized_chunk = chunk; + context.state.parallelized_chunks.push(chunk); + } + return; + } + } context.next(); } 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 b3f86c01d2..3336389686 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 @@ -148,20 +148,28 @@ export function Program(node, context) { for (const chunk of context.state.parallelized_chunks) { if (chunk.declarators.length === 1) { const declarator = chunk.declarators[0]; - body.splice( - chunk.position + offset, - 0, - b.declaration(chunk.kind, [ - b.declarator(declarator.id, b.call(b.await(b.call('$.save', declarator.init)))) - ]) - ); + if (declarator.id === null || chunk.kind === null) { + body.splice( + chunk.position + offset, + 0, + b.stmt(b.call(b.await(b.call('$.save', declarator.init)))) + ); + } else { + body.splice( + chunk.position + offset, + 0, + b.declaration(chunk.kind, [ + b.declarator(declarator.id, b.call(b.await(b.call('$.save', declarator.init)))) + ]) + ); + } } else { const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); - const init = b.call(`$.all`, ...chunk.declarators.map(({ init }) => init)); + const init = b.call('$.all', ...chunk.declarators.map(({ init }) => init)); body.splice( chunk.position + offset, 0, - b.declaration(chunk.kind, [b.declarator(pattern, b.await(init))]) + b.declaration(chunk.kind ?? 'const', [b.declarator(pattern, b.await(init))]) ); } offset++; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index ad9f6993d9..10a8c2f8fd 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -69,10 +69,14 @@ export function VariableDeclaration(node, context) { id, init: /** @type {Expression} */ (visited_init) }; - if (current_chunk && current_chunk.kind === node.kind) { + if ( + current_chunk && + (current_chunk.kind === node.kind || current_chunk.kind === null) + ) { current_chunk.declarators.push(_declarator); current_chunk.bindings.push(...bindings); current_chunk.position = /** @type {Program} */ (parent).body.indexOf(node); + current_chunk.kind = node.kind; } else { /** @type {ParallelizedChunk} */ const chunk = { @@ -370,10 +374,11 @@ export function VariableDeclaration(node, context) { id, init: /** @type {Expression} */ (init) })); - if (current_chunk && current_chunk.kind === node.kind) { + if (current_chunk && (current_chunk.kind === node.kind || current_chunk.kind === null)) { current_chunk.declarators.push(...declarators); current_chunk.bindings.push(...bindings); current_chunk.position = position; + current_chunk.kind = node.kind; } else { /** @type {ParallelizedChunk} */ const chunk = { From d399d8a0d56f2bf64f45465575b12d90a6d29631 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sat, 30 Aug 2025 17:25:17 -0700 Subject: [PATCH 28/37] fix --- .../phases/3-transform/client/visitors/ExpressionStatement.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js index 75c003c0ad..72b20bd837 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js @@ -42,7 +42,7 @@ export function ExpressionStatement(node, context) { if (parallelize) { const declarator = { id: null, - init: /** @type {Expression} */ (context.visit(node.expression)) + init: /** @type {Expression} */ (context.visit(node.expression.argument)) }; if (current_chunk) { current_chunk.declarators.push(declarator); From a819a6721cb49b9bb81238f082cc3b4e9eb469e4 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sat, 30 Aug 2025 17:27:06 -0700 Subject: [PATCH 29/37] fix? --- .../compiler/phases/3-transform/client/visitors/Program.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 3336389686..8dbe245d8d 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 @@ -169,7 +169,9 @@ export function Program(node, context) { body.splice( chunk.position + offset, 0, - b.declaration(chunk.kind ?? 'const', [b.declarator(pattern, b.await(init))]) + b.declaration(chunk.kind ?? 'const', [ + b.declarator(pattern, b.call(b.await(b.call('$.save', init)))) + ]) ); } offset++; From 01d6a75d57c875978a00bd090b173333450da586 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sat, 30 Aug 2025 23:33:50 -0700 Subject: [PATCH 30/37] try parallelizing awaited `$state` --- .../client/visitors/VariableDeclaration.js | 94 +++++++++++++++---- packages/svelte/src/internal/client/index.js | 1 + .../src/internal/client/reactivity/async.js | 12 +++ 3 files changed, 91 insertions(+), 16 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 10a8c2f8fd..05e37ca4f3 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -176,45 +176,83 @@ export function VariableDeclaration(node, context) { const value = /** @type {Expression} */ (args[0]) ?? b.void0; // TODO do we need the void 0? can we just omit it altogether? if (rune === '$state' || rune === '$state.raw') { + const state_declarators = []; + const current_chunk = context.state.current_parallelized_chunk; + const parallelize = + declarator.id.type === 'Identifier' && + context.state.analysis.instance?.scope === context.state.scope && + value.type === 'AwaitExpression' && + can_be_parallelized(value.argument, context.state.scope, context.state.analysis, [ + ...(current_chunk?.bindings ?? []), + ...bindings + ]); /** * @param {Identifier} id + * @param {Expression} visited * @param {Expression} value */ - const create_state_declarator = (id, value) => { + const create_state_declarator = (id, visited, value) => { const binding = /** @type {Binding} */ (context.state.scope.get(id.name)); const is_state = is_state_source(binding, context.state.analysis); - const is_proxy = should_proxy(value, context.state.scope); + const is_proxy = should_proxy(visited, context.state.scope); + const compose = []; + if (parallelize) { + if (rune === '$state' && is_proxy) { + compose.push(b.id('$.proxy')); - if (rune === '$state' && is_proxy) { - value = b.call('$.proxy', value); + if (dev && !is_state) { + compose.push( + b.arrow([b.id('proxy')], b.call('$.tag_proxy', b.id('proxy'), b.literal(id.name))) + ); + } + } - if (dev && !is_state) { - value = b.call('$.tag_proxy', value, b.literal(id.name)); + if (is_state) { + compose.push(b.id('$.state')); + if (dev) { + compose.push( + b.arrow([b.id('source')], b.call('$.tag', b.id('source'), b.literal(id.name))) + ); + } + } + } else { + if (rune === '$state' && is_proxy) { + value = b.call('$.proxy', value); + + if (dev && !is_state) { + value = b.call('$.tag_proxy', value, b.literal(id.name)); + } } - } - if (is_state) { - value = b.call('$.state', value); + if (is_state) { + value = b.call('$.state', value); - if (dev) { - value = b.call('$.tag', value, b.literal(id.name)); + if (dev) { + value = b.call('$.tag', value, b.literal(id.name)); + } } } - return value; + return parallelize && value.type === 'AwaitExpression' + ? b.call( + '$.async_compose', + /** @type {Expression} */ (context.visit(value.argument)), + ...compose + ) + : visited; }; if (declarator.id.type === 'Identifier') { const expression = /** @type {Expression} */ (context.visit(value)); - declarations.push( - b.declarator(declarator.id, create_state_declarator(declarator.id, expression)) + state_declarators.push( + b.declarator(declarator.id, create_state_declarator(declarator.id, expression, value)) ); } else { const tmp = b.id(context.state.scope.generate('tmp')); const { inserts, paths } = extract_paths(declarator.id, tmp); - declarations.push( + state_declarators.push( b.declarator(tmp, /** @type {Expression} */ (context.visit(value))), ...inserts.map(({ id, value }) => { id.name = context.state.scope.generate('$$array'); @@ -236,12 +274,36 @@ export function VariableDeclaration(node, context) { return b.declarator( path.node, binding?.kind === 'state' || binding?.kind === 'raw_state' - ? create_state_declarator(binding.node, value) + ? create_state_declarator(binding.node, value, path.expression) : value ); }) ); } + if (!parallelize) { + declarations.push(...state_declarators); + } else { + const declarators = state_declarators.map(({ id, init }) => ({ + id, + init: /** @type {Expression} */ (init) + })); + if (current_chunk && (current_chunk.kind === node.kind || current_chunk.kind === null)) { + current_chunk.declarators.push(...declarators); + current_chunk.bindings.push(...bindings); + current_chunk.position = position; + current_chunk.kind = node.kind; + } else { + /** @type {ParallelizedChunk} */ + const chunk = { + kind: node.kind, + declarators, + position, + bindings + }; + context.state.current_parallelized_chunk = chunk; + context.state.parallelized_chunks.push(chunk); + } + } continue; } diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index 04dd4cfb13..73628ef72f 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -101,6 +101,7 @@ export { export { all, async_body, + async_compose, for_await_track_reactivity_loss, save, track_reactivity_loss diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js index 181c33e9b9..0b404920b8 100644 --- a/packages/svelte/src/internal/client/reactivity/async.js +++ b/packages/svelte/src/internal/client/reactivity/async.js @@ -202,3 +202,15 @@ export function all(...promises) { ) ); } + +/** + * @param {Promise} promise + * @param {Array<(arg: any) => any>} fns + */ +export async function async_compose(promise, ...fns) { + let res = await promise; + for (const fn of fns) { + res = fn(res); + } + return res; +} From 41eeabaa4b2779e535cf456666a1e72ee8b02768 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sat, 30 Aug 2025 23:41:43 -0700 Subject: [PATCH 31/37] eh that'll work for now --- .../phases/3-transform/client/visitors/VariableDeclaration.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 05e37ca4f3..0469577401 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -216,6 +216,7 @@ export function VariableDeclaration(node, context) { } } } else { + value = visited; if (rune === '$state' && is_proxy) { value = b.call('$.proxy', value); From 24164f9a9d0bc16d287e2c8017fde867e42b53ca Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sat, 30 Aug 2025 23:47:08 -0700 Subject: [PATCH 32/37] fix --- .../3-transform/client/visitors/ExpressionStatement.js | 2 ++ .../3-transform/client/visitors/VariableDeclaration.js | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js index 72b20bd837..d5b7115e7b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js @@ -1,6 +1,7 @@ /** @import { Expression, ExpressionStatement, Node, Program } from 'estree' */ /** @import { ComponentContext, ParallelizedChunk } from '../types' */ import * as b from '#compiler/builders'; +import { is_expression_async } from '../../../../utils/ast.js'; import { get_rune } from '../../../scope.js'; import { can_be_parallelized } from '../utils.js'; @@ -30,6 +31,7 @@ export function ExpressionStatement(node, context) { } if ( node.expression.type === 'AwaitExpression' && + !is_expression_async(node.expression.argument) && context.state.analysis.instance?.scope === context.state.scope ) { const current_chunk = context.state.current_parallelized_chunk; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 0469577401..36ba43b84b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -2,7 +2,7 @@ /** @import { Binding } from '#compiler' */ /** @import { ComponentContext, ParallelizedChunk } from '../types' */ import { dev, is_ignored, locate_node } from '../../../../state.js'; -import { extract_paths } from '../../../../utils/ast.js'; +import { extract_paths, is_expression_async } from '../../../../utils/ast.js'; import * as b from '#compiler/builders'; import * as assert from '../../../../utils/assert.js'; import { get_rune } from '../../../scope.js'; @@ -49,7 +49,8 @@ export function VariableDeclaration(node, context) { } if ( init?.type === 'AwaitExpression' && - context.state.analysis.instance?.scope === context.state.scope + context.state.analysis.instance?.scope === context.state.scope && + !is_expression_async(init.argument) ) { const current_chunk = context.state.current_parallelized_chunk; const parallelize = can_be_parallelized( @@ -182,6 +183,7 @@ export function VariableDeclaration(node, context) { declarator.id.type === 'Identifier' && context.state.analysis.instance?.scope === context.state.scope && value.type === 'AwaitExpression' && + !is_expression_async(value.argument) && can_be_parallelized(value.argument, context.state.scope, context.state.analysis, [ ...(current_chunk?.bindings ?? []), ...bindings @@ -317,10 +319,12 @@ export function VariableDeclaration(node, context) { const current_chunk = context.state.current_parallelized_chunk; if ( is_async && + init.type === 'AwaitExpression' && context.state.analysis.instance && context.state.scope === context.state.analysis.instance.scope && // TODO make it work without this - declarator.id.type === 'Identifier' + declarator.id.type === 'Identifier' && + !is_expression_async(init.argument) ) { parallelize = can_be_parallelized(value, context.state.scope, context.state.analysis, [ ...(current_chunk?.bindings ?? []), From eb61f7a62f781813d4270ceed5a2fa5953ecd492 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sat, 30 Aug 2025 23:53:47 -0700 Subject: [PATCH 33/37] tweak --- .../phases/3-transform/client/visitors/VariableDeclaration.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 36ba43b84b..29b9db25ae 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -319,12 +319,10 @@ export function VariableDeclaration(node, context) { const current_chunk = context.state.current_parallelized_chunk; if ( is_async && - init.type === 'AwaitExpression' && context.state.analysis.instance && context.state.scope === context.state.analysis.instance.scope && // TODO make it work without this - declarator.id.type === 'Identifier' && - !is_expression_async(init.argument) + declarator.id.type === 'Identifier' ) { parallelize = can_be_parallelized(value, context.state.scope, context.state.analysis, [ ...(current_chunk?.bindings ?? []), From 4ee33d4890b372583658ed048e7b618ec5cfdc73 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sun, 31 Aug 2025 00:06:04 -0700 Subject: [PATCH 34/37] ok *this* should fix it --- .../client/visitors/VariableDeclaration.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index 29b9db25ae..92120b01bb 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -1,4 +1,4 @@ -/** @import { CallExpression, Expression, Identifier, Literal, Node, Program, VariableDeclaration, VariableDeclarator } from 'estree' */ +/** @import { AwaitExpression, CallExpression, Expression, Identifier, Literal, Node, Program, VariableDeclaration, VariableDeclarator } from 'estree' */ /** @import { Binding } from '#compiler' */ /** @import { ComponentContext, ParallelizedChunk } from '../types' */ import { dev, is_ignored, locate_node } from '../../../../state.js'; @@ -217,8 +217,15 @@ export function VariableDeclaration(node, context) { ); } } + return b.call( + '$.async_compose', + /** @type {Expression} */ ( + context.visit(/** @type {AwaitExpression} */ (value).argument) + ), + ...compose + ); } else { - value = visited; + let value = visited; if (rune === '$state' && is_proxy) { value = b.call('$.proxy', value); @@ -234,15 +241,8 @@ export function VariableDeclaration(node, context) { value = b.call('$.tag', value, b.literal(id.name)); } } + return value; } - - return parallelize && value.type === 'AwaitExpression' - ? b.call( - '$.async_compose', - /** @type {Expression} */ (context.visit(value.argument)), - ...compose - ) - : visited; }; if (declarator.id.type === 'Identifier') { From 1080beb8580c5d8a467cd9d9640ea0f01e5f15d9 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sun, 31 Aug 2025 00:09:45 -0700 Subject: [PATCH 35/37] remove unused --- .../svelte/src/compiler/phases/3-transform/client/utils.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index efb06c4996..aae95add35 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -98,9 +98,6 @@ export function can_be_parallelized(expression, scope, analysis, bindings) { return false; } } - if (!binding.mutated && !binding.reassigned) { - continue; - } } return true; } From e2c32f94f1128e6d053054afd3bc1db3d0c7d176 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sun, 31 Aug 2025 00:15:30 -0700 Subject: [PATCH 36/37] dedupe parallelized `await` stmts --- .../phases/3-transform/client/visitors/ExpressionStatement.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js index d5b7115e7b..90e40f7277 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/ExpressionStatement.js @@ -60,7 +60,7 @@ export function ExpressionStatement(node, context) { context.state.current_parallelized_chunk = chunk; context.state.parallelized_chunks.push(chunk); } - return; + return b.empty; } } From 06d43dfdf5cd24c191ec3c16ef387cfe9e8a8536 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Sun, 31 Aug 2025 02:33:37 -0700 Subject: [PATCH 37/37] make `$.all` a stmt if all awaits are stmts --- .../3-transform/client/visitors/Program.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) 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 8dbe245d8d..cee3a7aaf1 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 @@ -165,14 +165,18 @@ export function Program(node, context) { } } else { const pattern = b.array_pattern(chunk.declarators.map(({ id }) => id)); - const init = b.call('$.all', ...chunk.declarators.map(({ init }) => init)); - body.splice( - chunk.position + offset, - 0, - b.declaration(chunk.kind ?? 'const', [ - b.declarator(pattern, b.call(b.await(b.call('$.save', init)))) - ]) + const init = b.call( + b.await(b.call('$.save', b.call('$.all', ...chunk.declarators.map(({ init }) => init)))) ); + if (pattern.elements.every((element) => element === null)) { + body.splice(chunk.position + offset, 0, b.stmt(init)); + } else { + body.splice( + chunk.position + offset, + 0, + b.declaration(chunk.kind ?? 'const', [b.declarator(pattern, init)]) + ); + } } offset++; }