From 5f6525f4169f097bdad1b2b276c2d94f55fdbc01 Mon Sep 17 00:00:00 2001 From: ComputerGuy <63362464+Ocean-OS@users.noreply.github.com> Date: Mon, 20 Jan 2025 02:20:09 -0800 Subject: [PATCH] fix: omit unnecessary nullish coallescing in template expressions (#15056) * omit unnecessary nullish coallescing in template expressions * add tests --- .changeset/cuddly-walls-pretend.md | 5 +++ .../client/visitors/shared/utils.js | 17 +++++++++- .../nullish-coallescence-omittance/_config.js | 3 ++ .../_expected/client/index.svelte.js | 34 +++++++++++++++++++ .../_expected/server/index.svelte.js | 8 +++++ .../index.svelte | 8 +++++ 6 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 .changeset/cuddly-walls-pretend.md create mode 100644 packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_config.js create mode 100644 packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client/index.svelte.js create mode 100644 packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/server/index.svelte.js create mode 100644 packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/index.svelte diff --git a/.changeset/cuddly-walls-pretend.md b/.changeset/cuddly-walls-pretend.md new file mode 100644 index 000000000000..f51147a30cdd --- /dev/null +++ b/.changeset/cuddly-walls-pretend.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: omit unnecessary nullish coallescing in template expressions 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 9dd29843299b..c4f81274d97e 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 @@ -119,7 +119,22 @@ export function build_template_chunk( // extra work in the template_effect (instead we do the work in set_text). return { value, has_state }; } else { - expressions.push(b.logical('??', value, b.literal(''))); + let expression = value; + // only add nullish coallescence if it hasn't been added already + if (value.type === 'LogicalExpression' && value.operator === '??') { + const { right } = value; + // `undefined` isn't a Literal (due to pre-ES5 shenanigans), so the only nullish literal is `null` + // however, you _can_ make a variable called `undefined` in a Svelte component, so we can't just treat it the same way + if (right.type !== 'Literal') { + expression = b.logical('??', value, b.literal('')); + } else if (right.value === null) { + // if they do something weird like `stuff ?? null`, replace `null` with empty string + value.right = b.literal(''); + } + } else { + expression = b.logical('??', value, b.literal('')); + } + expressions.push(expression); } quasi = b.quasi('', i + 1 === values.length); diff --git a/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_config.js b/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_config.js new file mode 100644 index 000000000000..f47bee71df87 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client/index.svelte.js new file mode 100644 index 000000000000..332c909ebed9 --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/client/index.svelte.js @@ -0,0 +1,34 @@ +import 'svelte/internal/disclose-version'; +import * as $ from 'svelte/internal/client'; + +var on_click = (_, count) => $.update(count); +var root = $.template(`
`, 1); + +export default function Nullish_coallescence_omittance($$anchor) { + let name = 'world'; + let count = $.state(0); + var fragment = root(); + var h1 = $.first_child(fragment); + + h1.textContent = `Hello, ${name ?? ''}!`; + + var b = $.sibling(h1, 2); + + b.textContent = `${1 ?? 'stuff'}${2 ?? 'more stuff'}${3 ?? 'even more stuff'}`; + + var button = $.sibling(b, 2); + + button.__click = [on_click, count]; + + var text = $.child(button); + + $.reset(button); + + var h1_1 = $.sibling(button, 2); + + h1_1.textContent = `Hello, ${name ?? 'earth' ?? ''}`; + $.template_effect(() => $.set_text(text, `Count is ${$.get(count) ?? ''}`)); + $.append($$anchor, fragment); +} + +$.delegate(['click']); \ No newline at end of file diff --git a/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/server/index.svelte.js new file mode 100644 index 000000000000..8181bfd98eeb --- /dev/null +++ b/packages/svelte/tests/snapshot/samples/nullish-coallescence-omittance/_expected/server/index.svelte.js @@ -0,0 +1,8 @@ +import * as $ from 'svelte/internal/server'; + +export default function Nullish_coallescence_omittance($$payload) { + let name = 'world'; + let count = 0; + + $$payload.out += `