From 214f02581b8bf18d7d5184e20185e56ffaf4f20f Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Wed, 9 Oct 2024 13:02:20 +0100 Subject: [PATCH 1/4] fix: ensure set_text applies coercion to objects before diff --- .changeset/wet-hats-peel.md | 5 +++++ packages/svelte/src/internal/client/render.js | 4 ++++ .../samples/array-to-string/_config.js | 14 ++++++++++++++ .../samples/array-to-string/main.svelte | 11 +++++++++++ 4 files changed, 34 insertions(+) create mode 100644 .changeset/wet-hats-peel.md create mode 100644 packages/svelte/tests/runtime-runes/samples/array-to-string/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/array-to-string/main.svelte diff --git a/.changeset/wet-hats-peel.md b/.changeset/wet-hats-peel.md new file mode 100644 index 000000000000..fd67097f5f1b --- /dev/null +++ b/.changeset/wet-hats-peel.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure set_text applies coercion to objects before diff diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index de986ae04e08..f3ae159b8551 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -48,6 +48,10 @@ export function set_should_intro(value) { * @returns {void} */ export function set_text(text, value) { + // For objects, we apply string coercion before diffing + if (typeof value === 'object' && value !== null) { + value = value + ''; + } // @ts-expect-error if (value !== (text.__t ??= text.nodeValue)) { // @ts-expect-error diff --git a/packages/svelte/tests/runtime-runes/samples/array-to-string/_config.js b/packages/svelte/tests/runtime-runes/samples/array-to-string/_config.js new file mode 100644 index 000000000000..cd4716b2fc12 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/array-to-string/_config.js @@ -0,0 +1,14 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + const btn = target.querySelector('button'); + btn?.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + `1,2,3,4` + ); + } +}); diff --git a/packages/svelte/tests/runtime-runes/samples/array-to-string/main.svelte b/packages/svelte/tests/runtime-runes/samples/array-to-string/main.svelte new file mode 100644 index 000000000000..094d146a61b5 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/array-to-string/main.svelte @@ -0,0 +1,11 @@ + + + + +{array} From 955c9597c04fe1f4238ef80eaf838b20760b1ef3 Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Wed, 9 Oct 2024 13:02:53 +0100 Subject: [PATCH 2/4] lint --- .../tests/runtime-runes/samples/array-to-string/_config.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/svelte/tests/runtime-runes/samples/array-to-string/_config.js b/packages/svelte/tests/runtime-runes/samples/array-to-string/_config.js index cd4716b2fc12..800073e1d2cc 100644 --- a/packages/svelte/tests/runtime-runes/samples/array-to-string/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/array-to-string/_config.js @@ -6,9 +6,6 @@ export default test({ const btn = target.querySelector('button'); btn?.click(); flushSync(); - assert.htmlEqual( - target.innerHTML, - `1,2,3,4` - ); + assert.htmlEqual(target.innerHTML, `1,2,3,4`); } }); From 0b7d37cf8d95d1ad5ec57e66c36cb42a82c7243c Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Wed, 9 Oct 2024 13:07:38 +0100 Subject: [PATCH 3/4] feedback --- packages/svelte/src/internal/client/render.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index f3ae159b8551..f10256655328 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -49,14 +49,12 @@ export function set_should_intro(value) { */ export function set_text(text, value) { // For objects, we apply string coercion before diffing - if (typeof value === 'object' && value !== null) { - value = value + ''; - } + var str = value == null ? '' : typeof value === 'object' ? value + '' : value; // @ts-expect-error - if (value !== (text.__t ??= text.nodeValue)) { + if (str !== (text.__t ??= text.nodeValue)) { // @ts-expect-error - text.__t = value; - text.nodeValue = value == null ? '' : value + ''; + text.__t = str; + text.nodeValue = str == null ? '' : str + ''; } } From bf7637b1cb3331d40f327cc6b6a984111146582e Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Wed, 9 Oct 2024 13:54:27 +0100 Subject: [PATCH 4/4] Update packages/svelte/src/internal/client/render.js Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> --- packages/svelte/src/internal/client/render.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index f10256655328..16e2eb0d4e84 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -48,7 +48,7 @@ export function set_should_intro(value) { * @returns {void} */ export function set_text(text, value) { - // For objects, we apply string coercion before diffing + // For objects, we apply string coercion (which might make things like $state array references in the template reactive) before diffing var str = value == null ? '' : typeof value === 'object' ? value + '' : value; // @ts-expect-error if (str !== (text.__t ??= text.nodeValue)) {