Skip to content

Commit

Permalink
feat: better generated each block code in SSR mode (#13060)
Browse files Browse the repository at this point in the history
* chore: tidy up each block code

* groundwork

* cache length

* changeset

* regenerate
  • Loading branch information
Rich-Harris authored Aug 29, 2024
1 parent 3b8801c commit 588d636
Show file tree
Hide file tree
Showing 11 changed files with 28 additions and 31 deletions.
5 changes: 5 additions & 0 deletions .changeset/red-maps-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

feat: better generated each block code in SSR mode
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,27 @@ 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);

const array_id = state.scope.root.unique('each_array');
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));
}

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)
);
Expand Down
5 changes: 1 addition & 4 deletions packages/svelte/src/compiler/phases/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 });

Expand Down Expand Up @@ -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
};
Expand Down
1 change: 0 additions & 1 deletion packages/svelte/src/compiler/types/template.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 10 additions & 12 deletions packages/svelte/src/compiler/utils/builders.js
Original file line number Diff line number Diff line change
Expand Up @@ -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} */
Expand Down Expand Up @@ -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)]);
}

/**
Expand All @@ -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)]);
}

/**
Expand All @@ -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)]);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)}, `;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ export default function Inline_module_vars($$anchor) {
$.set_attribute(img, "src", __ENHANCED_IMG_5__);
$.reset(picture);
$.append($$anchor, picture);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ const __ENHANCED_IMG_6__ = "__VITE_ASSET__2AM7_y_f__";

export default function Inline_module_vars($$payload) {
$$payload.out += `<picture><source${$.attr("srcset", __ENHANCED_IMG_1__ + " 1440w, " + __ENHANCED_IMG_2__ + " 960w")} type="image/avif"> <source${$.attr("srcset", __ENHANCED_IMG_3__ + " 1440w, " + __ENHANCED_IMG_4__ + " 960w")} type="image/webp"> <source${$.attr("srcset", __ENHANCED_IMG_5__ + " 1440w, " + __ENHANCED_IMG_6__ + " 960w")} type="image/png"> <img${$.attr("src", __ENHANCED_IMG_5__)} alt="production test" width="1440" height="1440"></picture>`;
}
}
1 change: 0 additions & 1 deletion packages/svelte/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 588d636

Please sign in to comment.