fix(minifier): dce if statement should keep side effects and vars (#8433)

closes #7209

Note: Current output is sub-optimal.
This commit is contained in:
Boshen 2025-01-11 14:02:11 +00:00
parent 9a03bd23b9
commit 3c9354983d
4 changed files with 40 additions and 16 deletions

View file

@ -204,22 +204,33 @@ impl<'a, 'b> PeepholeRemoveDeadCode {
return Some(ctx.ast.statement_expression(if_stmt.span, expr));
}
match ctx.get_boolean_value(&if_stmt.test) {
Some(true) => Some(ctx.ast.move_statement(&mut if_stmt.consequent)),
Some(false) => {
Some(if let Some(alternate) = &mut if_stmt.alternate {
ctx.ast.move_statement(alternate)
if let Some(boolean) = ctx.get_side_free_boolean_value(&if_stmt.test) {
let mut keep_var = KeepVar::new(ctx.ast);
if boolean {
if let Some(alternate) = &if_stmt.alternate {
keep_var.visit_statement(alternate);
}
} else {
keep_var.visit_statement(&if_stmt.consequent);
};
if let Some(var_stmt) = keep_var.get_variable_declaration_statement() {
if boolean {
if_stmt.alternate = Some(var_stmt);
} else {
// Keep hoisted `vars` from the consequent block.
let mut keep_var = KeepVar::new(ctx.ast);
keep_var.visit_statement(&if_stmt.consequent);
keep_var
.get_variable_declaration_statement()
.unwrap_or_else(|| ctx.ast.statement_empty(SPAN))
})
if_stmt.consequent = var_stmt;
}
return None;
}
None => None,
return Some(if boolean {
ctx.ast.move_statement(&mut if_stmt.consequent)
} else {
if_stmt.alternate.as_mut().map_or_else(
|| ctx.ast.statement_empty(SPAN),
|alternate| ctx.ast.move_statement(alternate),
)
});
}
None
}
fn try_fold_for(

View file

@ -58,7 +58,7 @@ fn dce_if_statement() {
);
test(
"if (xxx) { foo } else if (false) { var a; var b; } else if (false) { var c; var d; }",
"if (xxx) foo; else var c, d;",
"if (xxx) foo; else if (false) var a, b; else if (false) var c, d;",
);
test("if (!false) { foo }", "foo");
@ -229,7 +229,7 @@ fn dce_from_terser() {
console.log(foo, bar, Baz);
",
"
var qux;
if (0) var qux;
console.log(foo, bar, Baz);
",
);

View file

@ -61,6 +61,19 @@ fn integration() {
);
test_same("a && (b && (c && (d && (e && (f && (g && (h && i && j && k && l && m && n && o && p && q && r && s && t && u && v && w && x && y && z)))))))");
test(
"if (((() => console.log('effect'))(), true)) {
} else {
var c = 1;
for (var c; unknownGlobal && true; unknownGlobal && true) var d;
}
console.log(c, d);
",
"if ((() => console.log('effect'))(), !0) {} else for (var c = 1, c; unknownGlobal; unknownGlobal && !0) var d;
console.log(c, d);
",
);
}
#[test] // https://github.com/oxc-project/oxc/issues/4341

View file

@ -21,7 +21,7 @@ Original | minified | minified | gzip | gzip | Fixture
3.20 MB | 1.01 MB | 1.01 MB | 331.79 kB | 331.56 kB | echarts.js
6.69 MB | 2.32 MB | 2.31 MB | 492.63 kB | 488.28 kB | antd.js
6.69 MB | 2.32 MB | 2.31 MB | 492.64 kB | 488.28 kB | antd.js
10.95 MB | 3.49 MB | 3.49 MB | 907.42 kB | 915.50 kB | typescript.js