From 808cc6fca6d44502930c0c5263a7cc3ecaed5f8c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 25 Mar 2024 22:01:22 -0400 Subject: [PATCH] feat: shorter each blocks (#10937) --- .changeset/three-lions-visit.md | 5 ++ .../3-transform/client/visitors/template.js | 56 +++++++++---------- .../src/internal/client/dom/blocks/each.js | 8 +-- .../_expected/client/index.svelte.js | 16 ++---- 4 files changed, 42 insertions(+), 43 deletions(-) create mode 100644 .changeset/three-lions-visit.md diff --git a/.changeset/three-lions-visit.md b/.changeset/three-lions-visit.md new file mode 100644 index 0000000000..a1576a4797 --- /dev/null +++ b/.changeset/three-lions-visit.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: more efficient each block compiler output diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index 7438b85fbc..71a51b9347 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -2314,12 +2314,6 @@ export const template_visitors = { // TODO should use context.visit? const children = create_block(node, 'each_block', node.body.nodes, context); - const else_block = node.fallback - ? b.arrow( - [b.id('$$anchor')], - /** @type {import('estree').BlockStatement} */ (context.visit(node.fallback)) - ) - : b.literal(null); const key_function = node.key ? b.arrow( [node.context.type === 'Identifier' ? node.context : b.id('$$item'), index], @@ -2337,6 +2331,11 @@ export const template_visitors = { declarations.push(b.let(node.index, index)); } + let callee = '$.each_indexed'; + + /** @type {import('estree').Expression[]} */ + const args = []; + if ((each_type & EACH_KEYED) !== 0) { if (context.state.options.dev && key_function.type !== 'Literal') { context.state.init.push( @@ -2344,33 +2343,34 @@ export const template_visitors = { ); } - context.state.after_update.push( - b.stmt( - b.call( - '$.each_keyed', - context.state.node, - each_node_meta.array_name ? each_node_meta.array_name : b.thunk(collection), - b.literal(each_type), - key_function, - b.arrow([b.id('$$anchor'), item, index], b.block(declarations.concat(children))), - else_block - ) - ) + callee = '$.each_keyed'; + + args.push( + context.state.node, + each_node_meta.array_name ? each_node_meta.array_name : b.thunk(collection), + b.literal(each_type), + key_function, + b.arrow([b.id('$$anchor'), item, index], b.block(declarations.concat(children))) ); } else { - context.state.after_update.push( - b.stmt( - b.call( - '$.each_indexed', - context.state.node, - each_node_meta.array_name ? each_node_meta.array_name : b.thunk(collection), - b.literal(each_type), - b.arrow([b.id('$$anchor'), item, index], b.block(declarations.concat(children))), - else_block - ) + args.push( + context.state.node, + each_node_meta.array_name ? each_node_meta.array_name : b.thunk(collection), + b.literal(each_type), + b.arrow([b.id('$$anchor'), item, index], b.block(declarations.concat(children))) + ); + } + + if (node.fallback) { + args.push( + b.arrow( + [b.id('$$anchor')], + /** @type {import('estree').BlockStatement} */ (context.visit(node.fallback)) ) ); } + + context.state.after_update.push(b.stmt(b.call(callee, ...args))); }, IfBlock(node, context) { context.state.template.push(''); diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js index 7d323b6ab9..d74f6adad5 100644 --- a/packages/svelte/src/internal/client/dom/blocks/each.js +++ b/packages/svelte/src/internal/client/dom/blocks/each.js @@ -197,10 +197,10 @@ function each(anchor, get_collection, flags, get_key, render_fn, fallback_fn, re * @param {number} flags * @param {null | ((item: V) => string)} get_key * @param {(anchor: null, item: V, index: import('#client').MaybeSource) => void} render_fn - * @param {null | ((anchor: Node | null) => void)} fallback_fn + * @param {null | ((anchor: Node | null) => void)} [fallback_fn] * @returns {void} */ -export function each_keyed(anchor, get_collection, flags, get_key, render_fn, fallback_fn) { +export function each_keyed(anchor, get_collection, flags, get_key, render_fn, fallback_fn = null) { each(anchor, get_collection, flags, get_key, render_fn, fallback_fn, reconcile_tracked_array); } @@ -210,10 +210,10 @@ export function each_keyed(anchor, get_collection, flags, get_key, render_fn, fa * @param {() => V[]} get_collection * @param {number} flags * @param {(anchor: null, item: V, index: import('#client').MaybeSource) => void} render_fn - * @param {null | ((anchor: Node | null) => void)} fallback_fn + * @param {null | ((anchor: Node | null) => void)} [fallback_fn] * @returns {void} */ -export function each_indexed(anchor, get_collection, flags, render_fn, fallback_fn) { +export function each_indexed(anchor, get_collection, flags, render_fn, fallback_fn = null) { each(anchor, get_collection, flags, null, render_fn, fallback_fn, reconcile_indexed_array); } diff --git a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js index 43f6d25f8c..06b05e4abf 100644 --- a/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js @@ -10,18 +10,12 @@ export default function Each_string_template($$anchor, $$props) { var fragment = $.comment($$anchor); var node = $.first_child(fragment); - $.each_indexed( - node, - () => ['foo', 'bar', 'baz'], - 1, - ($$anchor, thing, $$index) => { - var text = $.space_frag($$anchor); + $.each_indexed(node, () => ['foo', 'bar', 'baz'], 1, ($$anchor, thing, $$index) => { + var text = $.space_frag($$anchor); - $.render_effect(() => $.set_text(text, `${$.stringify($.unwrap(thing))}, `)); - return $.close($$anchor, text); - }, - null - ); + $.render_effect(() => $.set_text(text, `${$.stringify($.unwrap(thing))}, `)); + return $.close($$anchor, text); + }); $.close_frag($$anchor, fragment); $.pop();