From 76f5ecfdab2b65db9234d7fc2b59621a7b7c2dc5 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 5 Mar 2025 11:26:34 -0500 Subject: [PATCH] fix: never deduplicate expressions in templates (#15451) --- .changeset/five-wolves-swim.md | 5 ++ .../client/visitors/shared/utils.js | 46 ------------------- .../runtime-runes/samples/random/_config.js | 8 ++++ .../runtime-runes/samples/random/main.svelte | 6 +++ .../_expected/client/main.svelte.js | 6 +-- 5 files changed, 22 insertions(+), 49 deletions(-) create mode 100644 .changeset/five-wolves-swim.md create mode 100644 packages/svelte/tests/runtime-runes/samples/random/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/random/main.svelte diff --git a/.changeset/five-wolves-swim.md b/.changeset/five-wolves-swim.md new file mode 100644 index 0000000000..92178bed90 --- /dev/null +++ b/.changeset/five-wolves-swim.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: never deduplicate expressions in templates diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js index c25ef3ab50..df6308d631 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js @@ -26,55 +26,9 @@ export function memoize_expression(state, value) { * @param {Expression} value */ export function get_expression_id(state, value) { - for (let i = 0; i < state.expressions.length; i += 1) { - if (compare_expressions(state.expressions[i], value)) { - return b.id(`$${i}`); - } - } - return b.id(`$${state.expressions.push(value) - 1}`); } -/** - * Returns true of two expressions have an identical AST shape - * @param {Expression} a - * @param {Expression} b - */ -function compare_expressions(a, b) { - if (a.type !== b.type) { - return false; - } - - for (const key in a) { - if (key === 'type' || key === 'metadata' || key === 'loc' || key === 'start' || key === 'end') { - continue; - } - - const va = /** @type {any} */ (a)[key]; - const vb = /** @type {any} */ (b)[key]; - - if ((typeof va === 'object') !== (typeof vb === 'object')) { - return false; - } - - if (typeof va !== 'object' || va === null || vb === null) { - if (va !== vb) return false; - } else if (Array.isArray(va)) { - if (va.length !== vb.length) { - return false; - } - - if (va.some((v, i) => !compare_expressions(v, vb[i]))) { - return false; - } - } else if (!compare_expressions(va, vb)) { - return false; - } - } - - return true; -} - /** * @param {Array} values * @param {(node: AST.SvelteNode, state: any) => any} visit diff --git a/packages/svelte/tests/runtime-runes/samples/random/_config.js b/packages/svelte/tests/runtime-runes/samples/random/_config.js new file mode 100644 index 0000000000..368dd20c6c --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/random/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + const [p1, p2] = target.querySelectorAll('p'); + assert.notEqual(p1.textContent, p2.textContent); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/random/main.svelte b/packages/svelte/tests/runtime-runes/samples/random/main.svelte new file mode 100644 index 0000000000..e1ec0b5649 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/random/main.svelte @@ -0,0 +1,6 @@ + + +

{(Math.random() * m).toFixed(10)}

+

{(Math.random() * m).toFixed(10)}

diff --git a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js index d97a58bf40..219db6ffd5 100644 --- a/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js +++ b/packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js @@ -21,13 +21,13 @@ export default function Main($$anchor) { $.template_effect(() => $.set_custom_element_data(custom_element_1, 'fooBar', y())); $.template_effect( - ($0) => { + ($0, $1) => { $.set_attribute(div, 'foobar', x); $.set_attribute(svg, 'viewBox', x); $.set_attribute(div_1, 'foobar', $0); - $.set_attribute(svg_1, 'viewBox', $0); + $.set_attribute(svg_1, 'viewBox', $1); }, - [y] + [y, y] ); $.append($$anchor, fragment);