Skip to content

Commit 248089c

Browse files
committed
fix #4224: allow try statements to become dead
1 parent 42f159c commit 248089c

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,22 @@
281281
}
282282
```
283283
284+
* Improve tree-shaking of `try` statements in dead code ([#4224](https://github.com/evanw/esbuild/issues/4224))
285+
286+
With this release, esbuild will now remove certain `try` statements if esbuild considers them to be within dead code (i.e. code that is known to not ever be evaluated). For example:
287+
288+
```js
289+
// Original code
290+
return 'foo'
291+
try { return 'bar' } catch {}
292+
293+
// Old output (with --minify)
294+
return"foo";try{return"bar"}catch{}
295+
296+
// New output (with --minify)
297+
return"foo";
298+
```
299+
284300
* Update Go from 1.23.5 to 1.23.7 ([#4076](https://github.com/evanw/esbuild/issues/4076), [#4077](https://github.com/evanw/esbuild/pull/4077))
285301
286302
This should have no effect on existing code as this version change does not change Go's operating system support. It may remove certain reports from vulnerability scanners that detect which version of the Go compiler esbuild uses.

internal/js_parser/js_parser.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8614,6 +8614,15 @@ func findIdentifiers(binding js_ast.Binding, identifiers []js_ast.Decl) []js_ast
86148614
return identifiers
86158615
}
86168616

8617+
func shouldKeepStmtsInDeadControlFlow(stmts []js_ast.Stmt) bool {
8618+
for _, child := range stmts {
8619+
if shouldKeepStmtInDeadControlFlow(child) {
8620+
return true
8621+
}
8622+
}
8623+
return false
8624+
}
8625+
86178626
// If this is in a dead branch, then we want to trim as much dead code as we
86188627
// can. Everything can be trimmed except for hoisted declarations ("var" and
86198628
// "function"), which affect the parent scope. For example:
@@ -8650,12 +8659,12 @@ func shouldKeepStmtInDeadControlFlow(stmt js_ast.Stmt) bool {
86508659
return true
86518660

86528661
case *js_ast.SBlock:
8653-
for _, child := range s.Stmts {
8654-
if shouldKeepStmtInDeadControlFlow(child) {
8655-
return true
8656-
}
8657-
}
8658-
return false
8662+
return shouldKeepStmtsInDeadControlFlow(s.Stmts)
8663+
8664+
case *js_ast.STry:
8665+
return shouldKeepStmtsInDeadControlFlow(s.Block.Stmts) ||
8666+
(s.Catch != nil && shouldKeepStmtsInDeadControlFlow(s.Catch.Block.Stmts)) ||
8667+
(s.Finally != nil && shouldKeepStmtsInDeadControlFlow(s.Finally.Block.Stmts))
86598668

86608669
case *js_ast.SIf:
86618670
return shouldKeepStmtInDeadControlFlow(s.Yes) || (s.NoOrNil.Data != nil && shouldKeepStmtInDeadControlFlow(s.NoOrNil))

internal/js_parser/js_parser_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5429,6 +5429,24 @@ func TestTrimCodeInDeadControlFlow(t *testing.T) {
54295429
expectPrintedMangle(t, "if (1) a(); else { for(;;){var a} }", "if (1) a();\nelse\n for (; ; )\n var a;\n")
54305430
expectPrintedMangle(t, "if (1) { a(); b() } else { var a; var b; }", "if (1)\n a(), b();\nelse\n var a, b;\n")
54315431
expectPrintedMangle(t, "if (1) a(); else { switch (1) { case 1: case 2: var a } }", "if (1) a();\nelse\n var a;\n")
5432+
5433+
// See: https://github.com/evanw/esbuild/issues/4224
5434+
expectPrintedMangle(t, "return 'foo'; try { return 'bar' } catch {}", "return \"foo\";\n")
5435+
expectPrintedMangle(t, "return foo = true; try { var foo } catch {}", "return foo = true;\ntry {\n var foo;\n} catch {\n}\n")
5436+
expectPrintedMangle(t, "return foo = true; try {} catch { var foo }", "return foo = true;\ntry {\n} catch {\n var foo;\n}\n")
5437+
expectPrintedMangle(t, `
5438+
async function test() {
5439+
if (true) return { status: "disabled_for_development" };
5440+
try {
5441+
const response = await httpClients.releasesApi.get();
5442+
if (!response.ok) return { status: "no_release_found" };
5443+
if (response.statusCode === 204) return { status: "up_to_date" };
5444+
} catch (error) {
5445+
return { status: "no_release_found" };
5446+
}
5447+
return { status: "downloading" };
5448+
}
5449+
`, "async function test() {\n return { status: \"disabled_for_development\" };\n}\n")
54325450
}
54335451

54345452
func TestPreservedComments(t *testing.T) {

0 commit comments

Comments
 (0)