From 638483951a3a3a00fa2a03ae5d895a7a5e7c07ef Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Mon, 13 Nov 2023 16:11:00 +0000 Subject: [PATCH 1/4] Split $.each into $.each_keyed/$.each_indexed --- .github/PULL_REQUEST_TEMPLATE.md | 1 - .../3-transform/client/visitors/template.js | 39 +++++++++++----- .../svelte/src/internal/client/reconciler.js | 6 +-- packages/svelte/src/internal/client/render.js | 45 ++++++++++++------- 4 files changed, 60 insertions(+), 31 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e41d1e40c7ef..a4819f87baa5 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,6 @@ Please note that [the Svelte codebase is currently being rewritten for Svelte 5] If your PR concerns Svelte 4 (including updates to [svelte.dev.docs](https://svelte.dev/docs)), please ensure the base branch is `svelte-4` and not `main`. - ### Before submitting the PR, please make sure you do the following - [ ] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs 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 c80153a3272f..b8303677763a 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 @@ -2227,19 +2227,34 @@ export const template_visitors = { declarations.push(b.let(node.index, index)); } - context.state.after_update.push( - b.stmt( - b.call( - '$.each', - 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 + if ((each_type & EACH_KEYED) !== 0) { + 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 + ) ) - ) - ); + ); + } 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 + ) + ) + ); + } }, IfBlock(node, context) { context.state.template.push(''); diff --git a/packages/svelte/src/internal/client/reconciler.js b/packages/svelte/src/internal/client/reconciler.js index f0b0fce7c2c4..ded5c7ec2337 100644 --- a/packages/svelte/src/internal/client/reconciler.js +++ b/packages/svelte/src/internal/client/reconciler.js @@ -260,9 +260,9 @@ export function reconcile_indexed_array( * @param {Element | Comment | Text} dom * @param {boolean} is_controlled * @param {(anchor: null, item: V, index: number | import('./types.js').Signal) => void} render_fn - * @param {Array | null} keys * @param {number} flags * @param {boolean} apply_transitions + * @param {Array | null} keys * @returns {void} */ export function reconcile_tracked_array( @@ -271,9 +271,9 @@ export function reconcile_tracked_array( dom, is_controlled, render_fn, - keys, flags, - apply_transitions + apply_transitions, + keys ) { var a_blocks = each_block.items; const is_computed_key = keys !== null; diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index 2ef103363811..7ebf3d202ac3 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -2263,9 +2263,10 @@ export function each_item_block(item, key, index, render_fn, flags) { * @param {null | ((item: V) => string)} key_fn * @param {(anchor: null, item: V, index: import('./types.js').MaybeSignal) => void} render_fn * @param {null | ((anchor: Node) => void)} fallback_fn + * @param {typeof reconcile_indexed_array | reconcile_tracked_array} reconcile_fn * @returns {void} */ -export function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn) { +function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, reconcile_fn) { const is_controlled = (flags & EACH_IS_CONTROLLED) !== 0; const block = create_each_block(flags, anchor_node); @@ -2385,20 +2386,7 @@ export function each(anchor_node, collection, flags, key_fn, render_fn, fallback const flags = block.flags; const is_controlled = (flags & EACH_IS_CONTROLLED) !== 0; const anchor_node = block.anchor; - if ((flags & EACH_KEYED) !== 0) { - reconcile_tracked_array( - array, - block, - anchor_node, - is_controlled, - render_fn, - keys, - flags, - true - ); - } else { - reconcile_indexed_array(array, block, anchor_node, is_controlled, render_fn, flags, true); - } + reconcile_fn(array, block, anchor_node, is_controlled, render_fn, flags, true, keys); }, block, true @@ -2426,6 +2414,33 @@ export function each(anchor_node, collection, flags, key_fn, render_fn, fallback block.effect = each; } +/** + * @template V + * @param {Element | Comment} anchor_node + * @param {() => V[]} collection + * @param {number} flags + * @param {null | ((item: V) => string)} key_fn + * @param {(anchor: null, item: V, index: import('./types.js').MaybeSignal) => void} render_fn + * @param {null | ((anchor: Node) => void)} fallback_fn + * @returns {void} + */ +export function each_keyed(anchor_node, collection, flags, key_fn, render_fn, fallback_fn) { + each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, reconcile_tracked_array); +} + +/** + * @template V + * @param {Element | Comment} anchor_node + * @param {() => V[]} collection + * @param {number} flags + * @param {(anchor: null, item: V, index: import('./types.js').MaybeSignal) => void} render_fn + * @param {null | ((anchor: Node) => void)} fallback_fn + * @returns {void} + */ +export function each_indexed(anchor_node, collection, flags, render_fn, fallback_fn) { + each(anchor_node, collection, flags, null, render_fn, fallback_fn, reconcile_indexed_array); +} + /** * @param {Element | Text | Comment} anchor * @param {boolean} is_html From b99f559c781d91171cc948730fe8fd2e26f94672 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Mon, 13 Nov 2023 16:13:16 +0000 Subject: [PATCH 2/4] Add changeset --- .changeset/quiet-camels-mate.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/quiet-camels-mate.md diff --git a/.changeset/quiet-camels-mate.md b/.changeset/quiet-camels-mate.md new file mode 100644 index 000000000000..7c926c1ec1b8 --- /dev/null +++ b/.changeset/quiet-camels-mate.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +improve keyblock treeshaking From 6c6da4f8450c8d29b994fa45b1f8aa0b118be841 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:49:54 +0100 Subject: [PATCH 3/4] Update .changeset/quiet-camels-mate.md --- .changeset/quiet-camels-mate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/quiet-camels-mate.md b/.changeset/quiet-camels-mate.md index 7c926c1ec1b8..6e723bd4ab16 100644 --- a/.changeset/quiet-camels-mate.md +++ b/.changeset/quiet-camels-mate.md @@ -2,4 +2,4 @@ 'svelte': patch --- -improve keyblock treeshaking +chore: improve keyblock treeshaking From 6d50b22086beac255bd0e0e3444aecbe284de724 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Mon, 13 Nov 2023 16:55:53 +0000 Subject: [PATCH 4/4] Fix typo --- packages/svelte/src/internal/client/render.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index 7ebf3d202ac3..03c14f3740e2 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -68,7 +68,7 @@ import { hydrate_block_anchor, set_current_hydration_fragment } from './hydration.js'; -import { array_from, define_property, get_descriptor, get_descriptors, is_array } from './utils.js'; +import { array_from, define_property, get_descriptor, is_array } from './utils.js'; import { is_promise } from '../common.js'; import { bind_transition } from './transitions.js'; @@ -2408,7 +2408,7 @@ function each(anchor_node, collection, flags, key_fn, render_fn, fallback_fn, re fallback = fallback.prev; } // Clear the array - reconcile_indexed_array([], block, anchor_node, is_controlled, render_fn, flags, false); + reconcile_fn([], block, anchor_node, is_controlled, render_fn, flags, false, keys); destroy_signal(/** @type {import('./types.js').EffectSignal} */ (render)); }); block.effect = each;