diff --git a/packages/svelte/src/compiler/phases/1-parse/utils/create.js b/packages/svelte/src/compiler/phases/1-parse/utils/create.js index fbf5304d55..c184f49ed2 100644 --- a/packages/svelte/src/compiler/phases/1-parse/utils/create.js +++ b/packages/svelte/src/compiler/phases/1-parse/utils/create.js @@ -12,8 +12,7 @@ export function create_fragment(transparent = false) { metadata: { transparent, dynamic: false, - has_await: false, - is_async: false + has_await: false } }; } diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitBlock.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitBlock.js index b7dcbf1de4..16fad51679 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitBlock.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/AwaitBlock.js @@ -43,10 +43,6 @@ export function AwaitBlock(node, context) { context.visit(node.expression, { ...context.state, expression: node.metadata.expression }); - if (node.metadata.expression.has_await && context.state.fragment) { - context.state.fragment.metadata.is_async = true; - } - if (node.pending) context.visit(node.pending); if (node.then) context.visit(node.then); if (node.catch) context.visit(node.catch); diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/EachBlock.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/EachBlock.js index 6b9af8c8ba..e6a83921b1 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/EachBlock.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/EachBlock.js @@ -35,11 +35,6 @@ export function EachBlock(node, context) { scope: /** @type {Scope} */ (context.state.scope.parent) }); - // TODO it should be impossible to be in the template and not have a fragment... - if (node.metadata.expression.has_await && context.state.fragment) { - context.state.fragment.metadata.is_async = true; - } - context.visit(node.body); if (node.key) context.visit(node.key); if (node.fallback) context.visit(node.fallback); diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/IfBlock.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/IfBlock.js index aabfcc0c9d..dcdae3587f 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/IfBlock.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/IfBlock.js @@ -22,10 +22,6 @@ export function IfBlock(node, context) { expression: node.metadata.expression }); - if (node.metadata.expression.has_await && context.state.fragment) { - context.state.fragment.metadata.is_async = true; - } - context.visit(node.consequent); if (node.alternate) context.visit(node.alternate); } diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/AwaitBlock.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/AwaitBlock.js index 35e431f43d..ea60c95f68 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/AwaitBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/AwaitBlock.js @@ -1,29 +1,33 @@ -/** @import { BlockStatement, Expression, Pattern } from 'estree' */ +/** @import { BlockStatement, Expression, Pattern, Statement } from 'estree' */ /** @import { AST } from '#compiler' */ /** @import { ComponentContext } from '../types.js' */ import * as b from '#compiler/builders'; -import { block_close } from './shared/utils.js'; +import { block_close, call_child_payload } from './shared/utils.js'; /** * @param {AST.AwaitBlock} node * @param {ComponentContext} context */ export function AwaitBlock(node, context) { - context.state.template.push( - b.stmt( - b.call( - '$.await', - b.id('$$payload'), - /** @type {Expression} */ (context.visit(node.expression)), - b.thunk( - node.pending ? /** @type {BlockStatement} */ (context.visit(node.pending)) : b.block([]) - ), - b.arrow( - node.value ? [/** @type {Pattern} */ (context.visit(node.value))] : [], - node.then ? /** @type {BlockStatement} */ (context.visit(node.then)) : b.block([]) - ) + /** @type {Statement} */ + let statement = b.stmt( + b.call( + '$.await', + b.id('$$payload'), + /** @type {Expression} */ (context.visit(node.expression)), + b.thunk( + node.pending ? /** @type {BlockStatement} */ (context.visit(node.pending)) : b.block([]) + ), + b.arrow( + node.value ? [/** @type {Pattern} */ (context.visit(node.value))] : [], + node.then ? /** @type {BlockStatement} */ (context.visit(node.then)) : b.block([]) ) - ), - block_close + ) ); + + if (node.metadata.expression.has_await) { + statement = call_child_payload(b.block([statement]), true); + } + + context.state.template.push(statement, block_close); } diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/EachBlock.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/EachBlock.js index 7878ccf23a..0d1c03b695 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/EachBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/EachBlock.js @@ -2,7 +2,7 @@ /** @import { AST } from '#compiler' */ /** @import { ComponentContext } from '../types.js' */ import * as b from '#compiler/builders'; -import { block_close, block_open, block_open_else } from './shared/utils.js'; +import { block_close, block_open, block_open_else, call_child_payload } from './shared/utils.js'; /** * @param {AST.EachBlock} node @@ -17,7 +17,9 @@ export function EachBlock(node, context) { each_node_meta.contains_group_binding || !node.index ? each_node_meta.index : b.id(node.index); const array_id = state.scope.root.unique('each_array'); - state.init.push(b.const(array_id, b.call('$.ensure_array_like', collection))); + + /** @type {Statement} */ + let block = b.block([b.const(array_id, b.call('$.ensure_array_like', collection))]); /** @type {Statement[]} */ const each = []; @@ -47,19 +49,23 @@ export function EachBlock(node, context) { const fallback = /** @type {BlockStatement} */ (context.visit(node.fallback)); - fallback.body.unshift( - b.stmt(b.call(b.member(b.id('$$payload'), b.id('push')), block_open_else)) - ); + fallback.body.unshift(b.stmt(b.call(b.id('$$payload.push'), block_open_else))); - state.template.push( + block.body.push( b.if( b.binary('!==', b.member(array_id, 'length'), b.literal(0)), b.block([open, for_loop]), fallback - ), - block_close + ) ); } else { - state.template.push(block_open, for_loop, block_close); + state.template.push(block_open); + block.body.push(for_loop); + } + + if (node.metadata.expression.has_await) { + state.template.push(call_child_payload(block, true), block_close); + } else { + state.template.push(...block.body, block_close); } } diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/Fragment.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/Fragment.js index a44c7cfddd..a1d25980c4 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/Fragment.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/Fragment.js @@ -1,14 +1,8 @@ /** @import { AST } from '#compiler' */ -/** @import { Statement } from 'estree' */ /** @import { ComponentContext, ComponentServerTransformState } from '../types.js' */ import { clean_nodes, infer_namespace } from '../../utils.js'; import * as b from '#compiler/builders'; -import { - empty_comment, - process_children, - build_template, - call_child_payload -} from './shared/utils.js'; +import { empty_comment, process_children, build_template } from './shared/utils.js'; /** * @param {AST.Fragment} node @@ -48,15 +42,5 @@ export function Fragment(node, context) { process_children(trimmed, { ...context, state }); - if (node.metadata.is_async) { - /** @type {Statement[]} */ - const statements = []; - - statements.push(...state.init); - statements.push(...build_template(state.template)); - - return b.block([call_child_payload(b.block(statements), true)]); - } - return b.block([...state.init, ...build_template(state.template)]); } diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/IfBlock.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/IfBlock.js index 2ebf74a8e0..dd5f34d14e 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/IfBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/IfBlock.js @@ -1,8 +1,8 @@ -/** @import { BlockStatement, Expression } from 'estree' */ +/** @import { BlockStatement, Expression, Statement } from 'estree' */ /** @import { AST } from '#compiler' */ /** @import { ComponentContext } from '../types.js' */ import * as b from '#compiler/builders'; -import { block_close, block_open, block_open_else } from './shared/utils.js'; +import { block_close, block_open, block_open_else, call_child_payload } from './shared/utils.js'; /** * @param {AST.IfBlock} node @@ -22,5 +22,12 @@ export function IfBlock(node, context) { b.stmt(b.call(b.member(b.id('$$payload'), b.id('push')), block_open_else)) ); - context.state.template.push(b.if(test, consequent, alternate), block_close); + /** @type {Statement} */ + let statement = b.if(test, consequent, alternate); + + if (node.metadata.expression.has_await) { + statement = call_child_payload(b.block([statement]), true); + } + + context.state.template.push(statement, block_close); } diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js index a6ba1cb65e..29aad94a31 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js @@ -178,8 +178,7 @@ export function RegularElement(node, context) { b.id('$$payload'), b.arrow( [b.id('$$payload')], - b.block([...inner_state.init, ...build_template(inner_state.template)]), - node.fragment.metadata.is_async + b.block([...inner_state.init, ...build_template(inner_state.template)]) ) ) ) @@ -207,11 +206,7 @@ export function RegularElement(node, context) { ) ); } else { - if (node.fragment.metadata.is_async) { - state.template.push(/** @type {Statement} */ (context.visit(node.fragment))); - } else { - process_children(trimmed, { ...context, state }); - } + process_children(trimmed, { ...context, state }); } if (select_with_value) { diff --git a/packages/svelte/src/compiler/types/template.d.ts b/packages/svelte/src/compiler/types/template.d.ts index d5b7b86a10..42048c3525 100644 --- a/packages/svelte/src/compiler/types/template.d.ts +++ b/packages/svelte/src/compiler/types/template.d.ts @@ -57,8 +57,6 @@ export namespace AST { */ dynamic: boolean; has_await: boolean; - /** TODO document */ - is_async: boolean; }; } diff --git a/packages/svelte/tests/snapshot/samples/async-each-fallback-hoisting/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/async-each-fallback-hoisting/_expected/server/index.svelte.js index 08cf3148b2..0c66edc785 100644 --- a/packages/svelte/tests/snapshot/samples/async-each-fallback-hoisting/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/async-each-fallback-hoisting/_expected/server/index.svelte.js @@ -18,7 +18,7 @@ export default function Async_each_fallback_hoisting($$payload) { $$payload.push(``); $$payload.push(async () => $.escape(await Promise.resolve(4))); } - - $$payload.push(``); }); + + $$payload.push(``); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/async-each-hoisting/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/async-each-hoisting/_expected/server/index.svelte.js index 67c1e2dd8e..82235b76a7 100644 --- a/packages/svelte/tests/snapshot/samples/async-each-hoisting/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/async-each-hoisting/_expected/server/index.svelte.js @@ -5,18 +5,18 @@ export default function Async_each_hoisting($$payload) { const second = Promise.resolve(2); const third = Promise.resolve(3); + $$payload.push(``); + $$payload.child(async ($$payload) => { const each_array = $.ensure_array_like(await Promise.resolve([first, second, third])); - $$payload.push(``); - for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { let item = each_array[$$index]; $$payload.push(``); $$payload.push(async () => $.escape(await item)); } - - $$payload.push(``); }); + + $$payload.push(``); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/async-if-alternate-hoisting/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/async-if-alternate-hoisting/_expected/server/index.svelte.js index dcbb65e3d9..7b271ef0df 100644 --- a/packages/svelte/tests/snapshot/samples/async-if-alternate-hoisting/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/async-if-alternate-hoisting/_expected/server/index.svelte.js @@ -9,7 +9,7 @@ export default function Async_if_alternate_hoisting($$payload) { $$payload.push(''); $$payload.push(async () => $.escape(await Promise.resolve('yes yes yes'))); } - - $$payload.push(``); }); + + $$payload.push(``); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/async-if-hoisting/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/async-if-hoisting/_expected/server/index.svelte.js index df3af3db9d..ac06f01408 100644 --- a/packages/svelte/tests/snapshot/samples/async-if-hoisting/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/async-if-hoisting/_expected/server/index.svelte.js @@ -9,7 +9,7 @@ export default function Async_if_hoisting($$payload) { $$payload.push(''); $$payload.push(async () => $.escape(await Promise.reject('no no no'))); } - - $$payload.push(``); }); + + $$payload.push(``); } \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/delegated-locally-declared-shadowed/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/delegated-locally-declared-shadowed/_expected/server/index.svelte.js index 8f6aec31e2..a17c437cd9 100644 --- a/packages/svelte/tests/snapshot/samples/delegated-locally-declared-shadowed/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/delegated-locally-declared-shadowed/_expected/server/index.svelte.js @@ -1,10 +1,10 @@ import * as $ from 'svelte/internal/server'; export default function Delegated_locally_declared_shadowed($$payload) { - const each_array = $.ensure_array_like({ length: 1 }); - $$payload.push(``); + const each_array = $.ensure_array_like({ length: 1 }); + for (let index = 0, $$length = each_array.length; index < $$length; index++) { $$payload.push(``); } diff --git a/packages/svelte/tests/snapshot/samples/each-index-non-null/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-index-non-null/_expected/server/index.svelte.js index b1fbee9f60..abec4f42fa 100644 --- a/packages/svelte/tests/snapshot/samples/each-index-non-null/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/each-index-non-null/_expected/server/index.svelte.js @@ -1,10 +1,10 @@ import * as $ from 'svelte/internal/server'; export default function Each_index_non_null($$payload) { - const each_array = $.ensure_array_like(Array(10)); - $$payload.push(``); + const each_array = $.ensure_array_like(Array(10)); + for (let i = 0, $$length = each_array.length; i < $$length; i++) { $$payload.push(`
index: ${$.escape(i)}
`); } diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js index 6544baad6f..fda6e5fbb3 100644 --- a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/server/index.svelte.js @@ -1,10 +1,10 @@ import * as $ from 'svelte/internal/server'; export default function Each_string_template($$payload) { - const each_array = $.ensure_array_like(['foo', 'bar', 'baz']); - $$payload.push(``); + const each_array = $.ensure_array_like(['foo', 'bar', 'baz']); + for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { let thing = each_array[$$index];