Skip to content

Commit 8244508

Browse files
committed
minify unused ${x}y into ${x} instead of x+""
1 parent eef9253 commit 8244508

File tree

4 files changed

+54
-23
lines changed

4 files changed

+54
-23
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@
2626
""+1+2+3,""+(x?1:2)+y;
2727

2828
// New output (with --minify)
29-
x,""+y;
29+
x,`${y}`;
3030
```
3131

3232
This can arise when the template literals are nested inside of another function call that was determined to be unnecessary such as an unused call to a function marked with the `/* @__PURE__ */` pragma.
3333

34+
This release also fixes a bug with this transformation where minifying the unused expression `` `foo ${bar}` `` into `"" + bar` changed the meaning of the expression. Template string interpolation always calls `toString` while string addition may call `valueOf` instead. This unused expression is now minified to `` `${bar}` ``, which is slightly longer but which avoids the behavior change.
35+
3436
## 0.14.5
3537

3638
* Fix an issue with the publishing script

internal/js_parser/js_parser.go

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14218,29 +14218,32 @@ func (p *parser) simplifyUnusedExpr(expr js_ast.Expr) js_ast.Expr {
1421814218
case *js_ast.ETemplate:
1421914219
if e.TagOrNil.Data == nil {
1422014220
var comma js_ast.Expr
14221-
var concat js_ast.Expr
14221+
var templateLoc logger.Loc
14222+
var template *js_ast.ETemplate
1422214223
for _, part := range e.Parts {
14223-
// If we know this value is some kind of primitive, then we know that "ToString" has no side effects
14224+
// If we know this value is some kind of primitive, then we know that
14225+
// "ToString" has no side effects and can be avoided.
1422414226
if js_ast.KnownPrimitiveType(part.Value) != js_ast.PrimitiveUnknown {
14225-
if concat.Data != nil {
14226-
comma = js_ast.JoinWithComma(comma, concat)
14227-
concat.Data = nil
14227+
if template != nil {
14228+
comma = js_ast.JoinWithComma(comma, js_ast.Expr{Loc: templateLoc, Data: template})
14229+
template = nil
1422814230
}
1422914231
comma = js_ast.JoinWithComma(comma, p.simplifyUnusedExpr(part.Value))
1423014232
continue
1423114233
}
1423214234

14233-
// Make sure "ToString" is still evaluated on the value
14234-
if concat.Data == nil {
14235-
concat = js_ast.Expr{Loc: part.Value.Loc, Data: &js_ast.EString{}}
14235+
// Make sure "ToString" is still evaluated on the value. We can't use
14236+
// string addition here because that may evaluate "ValueOf" instead.
14237+
if template == nil {
14238+
template = &js_ast.ETemplate{}
14239+
templateLoc = part.Value.Loc
1423614240
}
14237-
concat = js_ast.Expr{Loc: part.Value.Loc, Data: &js_ast.EBinary{
14238-
Op: js_ast.BinOpAdd,
14239-
Left: concat,
14240-
Right: part.Value,
14241-
}}
14241+
template.Parts = append(template.Parts, js_ast.TemplatePart{Value: part.Value})
14242+
}
14243+
if template != nil {
14244+
comma = js_ast.JoinWithComma(comma, js_ast.Expr{Loc: templateLoc, Data: template})
1424214245
}
14243-
return js_ast.JoinWithComma(comma, concat)
14246+
return comma
1424414247
}
1424514248

1424614249
case *js_ast.EArray:

internal/js_parser/js_parser_test.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3813,14 +3813,16 @@ func TestMangleUnused(t *testing.T) {
38133813
}
38143814

38153815
expectPrintedMangle(t, "tag`a${b}c${d}e`", "tag`a${b}c${d}e`;\n")
3816-
expectPrintedMangle(t, "`a${b}c${d}e`", "\"\" + b + d;\n")
3817-
3818-
expectPrintedMangle(t, "`${x}${1}`", "\"\" + x;\n")
3819-
expectPrintedMangle(t, "`${1}${y}`", "\"\" + y;\n")
3820-
expectPrintedMangle(t, "`${x}${y}`", "\"\" + x + y;\n")
3821-
expectPrintedMangle(t, "`${x ? 1 : 2}${y}`", "x, \"\" + y;\n")
3822-
expectPrintedMangle(t, "`${x}${y ? 1 : 2}`", "\"\" + x, y;\n")
3823-
expectPrintedMangle(t, "`${x}${y ? 1 : 2}${z}`", "\"\" + x, y, \"\" + z;\n")
3816+
expectPrintedMangle(t, "`a${b}c${d}e`", "`${b}${d}`;\n")
3817+
3818+
// These can't be reduced to string addition due to "valueOf". See:
3819+
// https://github.com/terser/terser/issues/1128#issuecomment-994209801
3820+
expectPrintedMangle(t, "`stuff ${x} ${1}`", "`${x}`;\n")
3821+
expectPrintedMangle(t, "`stuff ${1} ${y}`", "`${y}`;\n")
3822+
expectPrintedMangle(t, "`stuff ${x} ${y}`", "`${x}${y}`;\n")
3823+
expectPrintedMangle(t, "`stuff ${x ? 1 : 2} ${y}`", "x, `${y}`;\n")
3824+
expectPrintedMangle(t, "`stuff ${x} ${y ? 1 : 2}`", "`${x}`, y;\n")
3825+
expectPrintedMangle(t, "`stuff ${x} ${y ? 1 : 2} ${z}`", "`${x}`, y, `${z}`;\n")
38243826

38253827
expectPrintedMangle(t, "'a' + b + 'c' + d", "\"\" + b + d;\n")
38263828
expectPrintedMangle(t, "a + 'b' + c + 'd'", "a + \"\" + c;\n")

scripts/end-to-end-tests.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,30 @@
693693
if (foo() === bar()) throw 'fail'
694694
`,
695695
}),
696+
697+
// Unused minified template literals. See this for more info:
698+
// https://github.com/terser/terser/issues/1128#issuecomment-994209801
699+
test(['in.js', '--outfile=node.js', '--minify', target], {
700+
'in.js': `
701+
var text = '';
702+
var foo = {
703+
toString: () => text += 'toString',
704+
valueOf: () => text += 'valueOf',
705+
};
706+
\`\${foo}\`;
707+
if (text !== 'toString') throw 'fail: ' + text + ' !== toString'
708+
`,
709+
}),
710+
test(['in.js', '--outfile=node.js', '--minify', target], {
711+
'in.js': `
712+
var text = '';
713+
var foo = {
714+
toString: () => text += 'toString',
715+
};
716+
\`abc \${text += 'A', foo} xyz \${text += 'B', foo} 123\`;
717+
if (text !== 'AtoStringBtoString') throw 'fail: ' + text + ' !== AtoStringBtoString'
718+
`,
719+
}),
696720
)
697721
}
698722

0 commit comments

Comments
 (0)