From 588d636ad6e9bee6f8c942e90a5ddf9786c4cd51 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 29 Aug 2024 16:55:30 -0400 Subject: [PATCH] feat: better generated each block code in SSR mode (#13060) * chore: tidy up each block code * groundwork * cache length * changeset * regenerate --- .changeset/red-maps-nail.md | 5 +++++ .../3-transform/client/visitors/EachBlock.js | 2 +- .../client/visitors/VariableDeclaration.js | 4 ++-- .../3-transform/server/visitors/EachBlock.js | 13 +++++------ packages/svelte/src/compiler/phases/scope.js | 5 +---- .../svelte/src/compiler/types/template.d.ts | 1 - .../svelte/src/compiler/utils/builders.js | 22 +++++++++---------- .../_expected/server/index.svelte.js | 2 +- .../_expected/client/index.svelte.js | 2 +- .../_expected/server/index.svelte.js | 2 +- packages/svelte/types/index.d.ts | 1 - 11 files changed, 28 insertions(+), 31 deletions(-) create mode 100644 .changeset/red-maps-nail.md diff --git a/.changeset/red-maps-nail.md b/.changeset/red-maps-nail.md new file mode 100644 index 0000000000..731a863440 --- /dev/null +++ b/.changeset/red-maps-nail.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: better generated each block code in SSR mode diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js index d787665121..5394bf9478 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/EachBlock.js @@ -147,7 +147,7 @@ export function EachBlock(node, context) { // which needs a reference to the index const index = each_node_meta.contains_group_binding || !node.index ? each_node_meta.index : b.id(node.index); - const item = each_node_meta.item; + const item = node.context.type === 'Identifier' ? node.context : b.id('$$item'); let uses_index = each_node_meta.contains_group_binding; let key_uses_index = false; 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 5f6f5bc79c..e4f6f57f72 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 @@ -32,7 +32,7 @@ export function VariableDeclaration(node, context) { ) { if (init != null && is_hoisted_function(init)) { context.state.hoisted.push( - b.declaration('const', declarator.id, /** @type {Expression} */ (context.visit(init))) + b.const(declarator.id, /** @type {Expression} */ (context.visit(init))) ); continue; @@ -205,7 +205,7 @@ export function VariableDeclaration(node, context) { if (init != null && is_hoisted_function(init)) { context.state.hoisted.push( - b.declaration('const', declarator.id, /** @type {Expression} */ (context.visit(init))) + b.const(declarator.id, /** @type {Expression} */ (context.visit(init))) ); continue; 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 dba37c1730..9595fd436a 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 @@ -14,7 +14,6 @@ export function EachBlock(node, context) { const each_node_meta = node.metadata; const collection = /** @type {Expression} */ (context.visit(node.expression)); - const item = each_node_meta.item; const index = each_node_meta.contains_group_binding || !node.index ? each_node_meta.index : b.id(node.index); @@ -22,11 +21,8 @@ export function EachBlock(node, context) { state.init.push(b.const(array_id, b.call('$.ensure_array_like', collection))); /** @type {Statement[]} */ - const each = [b.const(item, b.member(array_id, index, true))]; + const each = [b.const(/** @type {Pattern} */ (node.context), b.member(array_id, index, true))]; - if (node.context.type !== 'Identifier') { - each.push(b.const(/** @type {Pattern} */ (node.context), item)); - } if (index.name !== node.index && node.index != null) { each.push(b.let(node.index, index)); } @@ -34,8 +30,11 @@ export function EachBlock(node, context) { each.push(.../** @type {BlockStatement} */ (context.visit(node.body)).body); const for_loop = b.for( - b.let(index, b.literal(0)), - b.binary('<', index, b.member(array_id, 'length')), + b.declaration('let', [ + b.declarator(index, b.literal(0)), + b.declarator('$$length', b.member(array_id, 'length')) + ]), + b.binary('<', index, b.id('$$length')), b.update('++', index, false), b.block(each) ); diff --git a/packages/svelte/src/compiler/phases/scope.js b/packages/svelte/src/compiler/phases/scope.js index 007c39b319..7aea1e773b 100644 --- a/packages/svelte/src/compiler/phases/scope.js +++ b/packages/svelte/src/compiler/phases/scope.js @@ -547,9 +547,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) { binding.metadata = { inside_rest: is_rest_id }; } - if (node.context.type !== 'Identifier') { - scope.declare(b.id('$$item'), 'template', 'synthetic'); - } + // Visit to pick up references from default initializers visit(node.context, { scope }); @@ -583,7 +581,6 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) { contains_group_binding: false, array_name: needs_array_deduplication ? state.scope.root.unique('$$array') : null, index: scope.root.unique('$$index'), - item: node.context.type === 'Identifier' ? node.context : b.id('$$item'), declarations: scope.declarations, is_controlled: false }; diff --git a/packages/svelte/src/compiler/types/template.d.ts b/packages/svelte/src/compiler/types/template.d.ts index f72f07e448..888fd5c21b 100644 --- a/packages/svelte/src/compiler/types/template.d.ts +++ b/packages/svelte/src/compiler/types/template.d.ts @@ -405,7 +405,6 @@ export interface EachBlock extends BaseNode { /** Set if something in the array expression is shadowed within the each block */ array_name: Identifier | null; index: Identifier; - item: Identifier; declarations: Map; /** * Optimization path for each blocks: If the parent isn't a fragment and diff --git a/packages/svelte/src/compiler/utils/builders.js b/packages/svelte/src/compiler/utils/builders.js index 10f2b7a3ea..060a8c2990 100644 --- a/packages/svelte/src/compiler/utils/builders.js +++ b/packages/svelte/src/compiler/utils/builders.js @@ -176,27 +176,25 @@ export function logical(operator, left, right) { /** * @param {'const' | 'let' | 'var'} kind - * @param {string | ESTree.Pattern} pattern - * @param {ESTree.Expression} [init] + * @param {ESTree.VariableDeclarator[]} declarations * @returns {ESTree.VariableDeclaration} */ -export function declaration(kind, pattern, init) { - if (typeof pattern === 'string') pattern = id(pattern); - +export function declaration(kind, declarations) { return { type: 'VariableDeclaration', kind, - declarations: [init ? declarator(pattern, init) : declarator(pattern)] + declarations }; } /** - * @param {ESTree.Pattern} id + * @param {ESTree.Pattern | string} pattern * @param {ESTree.Expression} [init] * @returns {ESTree.VariableDeclarator} */ -export function declarator(id, init) { - return { type: 'VariableDeclarator', id, init }; +export function declarator(pattern, init) { + if (typeof pattern === 'string') pattern = id(pattern); + return { type: 'VariableDeclarator', id: pattern, init }; } /** @type {ESTree.EmptyStatement} */ @@ -491,7 +489,7 @@ const this_instance = { * @returns {ESTree.VariableDeclaration} */ function let_builder(pattern, init) { - return declaration('let', pattern, init); + return declaration('let', [declarator(pattern, init)]); } /** @@ -500,7 +498,7 @@ function let_builder(pattern, init) { * @returns {ESTree.VariableDeclaration} */ function const_builder(pattern, init) { - return declaration('const', pattern, init); + return declaration('const', [declarator(pattern, init)]); } /** @@ -509,7 +507,7 @@ function const_builder(pattern, init) { * @returns {ESTree.VariableDeclaration} */ function var_builder(pattern, init) { - return declaration('var', pattern, init); + return declaration('var', [declarator(pattern, init)]); } /** 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 9258fb7747..bb6b737b8e 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 @@ -5,7 +5,7 @@ export default function Each_string_template($$payload) { $$payload.out += ``; - for (let $$index = 0; $$index < each_array.length; $$index++) { + for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) { const thing = each_array[$$index]; $$payload.out += `${$.escape(thing)}, `; diff --git a/packages/svelte/tests/snapshot/samples/inline-module-vars/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/inline-module-vars/_expected/client/index.svelte.js index 6af688f180..8776c5c095 100644 --- a/packages/svelte/tests/snapshot/samples/inline-module-vars/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/inline-module-vars/_expected/client/index.svelte.js @@ -30,4 +30,4 @@ export default function Inline_module_vars($$anchor) { $.set_attribute(img, "src", __ENHANCED_IMG_5__); $.reset(picture); $.append($$anchor, picture); -} +} \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/inline-module-vars/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/inline-module-vars/_expected/server/index.svelte.js index 9e19c08fe6..5542d12573 100644 --- a/packages/svelte/tests/snapshot/samples/inline-module-vars/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/inline-module-vars/_expected/server/index.svelte.js @@ -9,4 +9,4 @@ const __ENHANCED_IMG_6__ = "__VITE_ASSET__2AM7_y_f__"; export default function Inline_module_vars($$payload) { $$payload.out += ` `; -} +} \ No newline at end of file diff --git a/packages/svelte/types/index.d.ts b/packages/svelte/types/index.d.ts index 7b2117cad1..87cf40d934 100644 --- a/packages/svelte/types/index.d.ts +++ b/packages/svelte/types/index.d.ts @@ -1866,7 +1866,6 @@ declare module 'svelte/compiler' { /** Set if something in the array expression is shadowed within the each block */ array_name: Identifier | null; index: Identifier; - item: Identifier; declarations: Map; /** * Optimization path for each blocks: If the parent isn't a fragment and