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 4 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
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;

@ -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;

@ -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)
);

@ -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
};

@ -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<string, Binding>;
/**
* 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 {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)]);
}
/**

@ -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)}, `;

@ -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<string, Binding>;
/**
* Optimization path for each blocks: If the parent isn't a fragment and

Loading…
Cancel
Save