feat: better generated each block code in SSR mode (#13060)

* chore: tidy up each block code

* groundwork

* cache length

* changeset

* regenerate
pull/13074/head
Rich Harris 5 months ago committed by GitHub
parent 3b8801cbba
commit 588d636ad6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
feat: better generated each block code in SSR mode

@ -147,7 +147,7 @@ export function EachBlock(node, context) {
// which needs a reference to the index // which needs a reference to the index
const index = const index =
each_node_meta.contains_group_binding || !node.index ? each_node_meta.index : b.id(node.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 uses_index = each_node_meta.contains_group_binding;
let key_uses_index = false; let key_uses_index = false;

@ -32,7 +32,7 @@ export function VariableDeclaration(node, context) {
) { ) {
if (init != null && is_hoisted_function(init)) { if (init != null && is_hoisted_function(init)) {
context.state.hoisted.push( context.state.hoisted.push(
b.declaration('const', declarator.id, /** @type {Expression} */ (context.visit(init))) b.const(declarator.id, /** @type {Expression} */ (context.visit(init)))
); );
continue; continue;
@ -205,7 +205,7 @@ export function VariableDeclaration(node, context) {
if (init != null && is_hoisted_function(init)) { if (init != null && is_hoisted_function(init)) {
context.state.hoisted.push( context.state.hoisted.push(
b.declaration('const', declarator.id, /** @type {Expression} */ (context.visit(init))) b.const(declarator.id, /** @type {Expression} */ (context.visit(init)))
); );
continue; continue;

@ -14,7 +14,6 @@ export function EachBlock(node, context) {
const each_node_meta = node.metadata; const each_node_meta = node.metadata;
const collection = /** @type {Expression} */ (context.visit(node.expression)); const collection = /** @type {Expression} */ (context.visit(node.expression));
const item = each_node_meta.item;
const index = const index =
each_node_meta.contains_group_binding || !node.index ? each_node_meta.index : b.id(node.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))); state.init.push(b.const(array_id, b.call('$.ensure_array_like', collection)));
/** @type {Statement[]} */ /** @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) { if (index.name !== node.index && node.index != null) {
each.push(b.let(node.index, index)); 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); each.push(.../** @type {BlockStatement} */ (context.visit(node.body)).body);
const for_loop = b.for( const for_loop = b.for(
b.let(index, b.literal(0)), b.declaration('let', [
b.binary('<', index, b.member(array_id, 'length')), 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.update('++', index, false),
b.block(each) b.block(each)
); );

@ -547,9 +547,7 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
binding.metadata = { inside_rest: is_rest_id }; 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 to pick up references from default initializers
visit(node.context, { scope }); visit(node.context, { scope });
@ -583,7 +581,6 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
contains_group_binding: false, contains_group_binding: false,
array_name: needs_array_deduplication ? state.scope.root.unique('$$array') : null, array_name: needs_array_deduplication ? state.scope.root.unique('$$array') : null,
index: scope.root.unique('$$index'), index: scope.root.unique('$$index'),
item: node.context.type === 'Identifier' ? node.context : b.id('$$item'),
declarations: scope.declarations, declarations: scope.declarations,
is_controlled: false is_controlled: false
}; };

@ -405,7 +405,6 @@ export interface EachBlock extends BaseNode {
/** Set if something in the array expression is shadowed within the each block */ /** Set if something in the array expression is shadowed within the each block */
array_name: Identifier | null; array_name: Identifier | null;
index: Identifier; index: Identifier;
item: Identifier;
declarations: Map<string, Binding>; declarations: Map<string, Binding>;
/** /**
* Optimization path for each blocks: If the parent isn't a fragment and * Optimization path for each blocks: If the parent isn't a fragment and

@ -176,27 +176,25 @@ export function logical(operator, left, right) {
/** /**
* @param {'const' | 'let' | 'var'} kind * @param {'const' | 'let' | 'var'} kind
* @param {string | ESTree.Pattern} pattern * @param {ESTree.VariableDeclarator[]} declarations
* @param {ESTree.Expression} [init]
* @returns {ESTree.VariableDeclaration} * @returns {ESTree.VariableDeclaration}
*/ */
export function declaration(kind, pattern, init) { export function declaration(kind, declarations) {
if (typeof pattern === 'string') pattern = id(pattern);
return { return {
type: 'VariableDeclaration', type: 'VariableDeclaration',
kind, kind,
declarations: [init ? declarator(pattern, init) : declarator(pattern)] declarations
}; };
} }
/** /**
* @param {ESTree.Pattern} id * @param {ESTree.Pattern | string} pattern
* @param {ESTree.Expression} [init] * @param {ESTree.Expression} [init]
* @returns {ESTree.VariableDeclarator} * @returns {ESTree.VariableDeclarator}
*/ */
export function declarator(id, init) { export function declarator(pattern, init) {
return { type: 'VariableDeclarator', id, init }; if (typeof pattern === 'string') pattern = id(pattern);
return { type: 'VariableDeclarator', id: pattern, init };
} }
/** @type {ESTree.EmptyStatement} */ /** @type {ESTree.EmptyStatement} */
@ -491,7 +489,7 @@ const this_instance = {
* @returns {ESTree.VariableDeclaration} * @returns {ESTree.VariableDeclaration}
*/ */
function let_builder(pattern, init) { 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} * @returns {ESTree.VariableDeclaration}
*/ */
function const_builder(pattern, init) { 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} * @returns {ESTree.VariableDeclaration}
*/ */
function var_builder(pattern, init) { function var_builder(pattern, init) {
return declaration('var', pattern, init); return declaration('var', [declarator(pattern, init)]);
} }
/** /**

@ -5,7 +5,7 @@ export default function Each_string_template($$payload) {
$$payload.out += `<!--[-->`; $$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]; const thing = each_array[$$index];
$$payload.out += `${$.escape(thing)}, `; $$payload.out += `${$.escape(thing)}, `;

@ -1866,7 +1866,6 @@ declare module 'svelte/compiler' {
/** Set if something in the array expression is shadowed within the each block */ /** Set if something in the array expression is shadowed within the each block */
array_name: Identifier | null; array_name: Identifier | null;
index: Identifier; index: Identifier;
item: Identifier;
declarations: Map<string, Binding>; declarations: Map<string, Binding>;
/** /**
* Optimization path for each blocks: If the parent isn't a fragment and * Optimization path for each blocks: If the parent isn't a fragment and

Loading…
Cancel
Save