Skip to content

Commit 5f6525f

Browse files
authored
fix: omit unnecessary nullish coallescing in template expressions (#15056)
* omit unnecessary nullish coallescing in template expressions * add tests
1 parent 700029b commit 5f6525f

File tree

6 files changed

+74
-1
lines changed

6 files changed

+74
-1
lines changed

.changeset/cuddly-walls-pretend.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: omit unnecessary nullish coallescing in template expressions

packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/utils.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,22 @@ export function build_template_chunk(
119119
// extra work in the template_effect (instead we do the work in set_text).
120120
return { value, has_state };
121121
} else {
122-
expressions.push(b.logical('??', value, b.literal('')));
122+
let expression = value;
123+
// only add nullish coallescence if it hasn't been added already
124+
if (value.type === 'LogicalExpression' && value.operator === '??') {
125+
const { right } = value;
126+
// `undefined` isn't a Literal (due to pre-ES5 shenanigans), so the only nullish literal is `null`
127+
// however, you _can_ make a variable called `undefined` in a Svelte component, so we can't just treat it the same way
128+
if (right.type !== 'Literal') {
129+
expression = b.logical('??', value, b.literal(''));
130+
} else if (right.value === null) {
131+
// if they do something weird like `stuff ?? null`, replace `null` with empty string
132+
value.right = b.literal('');
133+
}
134+
} else {
135+
expression = b.logical('??', value, b.literal(''));
136+
}
137+
expressions.push(expression);
123138
}
124139

125140
quasi = b.quasi('', i + 1 === values.length);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { test } from '../../test';
2+
3+
export default test({});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import 'svelte/internal/disclose-version';
2+
import * as $ from 'svelte/internal/client';
3+
4+
var on_click = (_, count) => $.update(count);
5+
var root = $.template(`<h1></h1> <b></b> <button> </button> <h1></h1>`, 1);
6+
7+
export default function Nullish_coallescence_omittance($$anchor) {
8+
let name = 'world';
9+
let count = $.state(0);
10+
var fragment = root();
11+
var h1 = $.first_child(fragment);
12+
13+
h1.textContent = `Hello, ${name ?? ''}!`;
14+
15+
var b = $.sibling(h1, 2);
16+
17+
b.textContent = `${1 ?? 'stuff'}${2 ?? 'more stuff'}${3 ?? 'even more stuff'}`;
18+
19+
var button = $.sibling(b, 2);
20+
21+
button.__click = [on_click, count];
22+
23+
var text = $.child(button);
24+
25+
$.reset(button);
26+
27+
var h1_1 = $.sibling(button, 2);
28+
29+
h1_1.textContent = `Hello, ${name ?? 'earth' ?? ''}`;
30+
$.template_effect(() => $.set_text(text, `Count is ${$.get(count) ?? ''}`));
31+
$.append($$anchor, fragment);
32+
}
33+
34+
$.delegate(['click']);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import * as $ from 'svelte/internal/server';
2+
3+
export default function Nullish_coallescence_omittance($$payload) {
4+
let name = 'world';
5+
let count = 0;
6+
7+
$$payload.out += `<h1>Hello, ${$.escape(name)}!</h1> <b>${$.escape(1 ?? 'stuff')}${$.escape(2 ?? 'more stuff')}${$.escape(3 ?? 'even more stuff')}</b> <button>Count is ${$.escape(count)}</button> <h1>Hello, ${$.escape(name ?? 'earth' ?? null)}</h1>`;
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script>
2+
let name = 'world';
3+
let count = $state(0);
4+
</script>
5+
<h1>Hello, {null}{name}!</h1>
6+
<b>{1 ?? 'stuff'}{2 ?? 'more stuff'}{3 ?? 'even more stuff'}</b>
7+
<button onclick={()=>count++}>Count is {count}</button>
8+
<h1>Hello, {name ?? 'earth' ?? null}</h1>

0 commit comments

Comments
 (0)