From 6c8ee9fdefd0e2541736e9c11002fa1c55ba6f63 Mon Sep 17 00:00:00 2001 From: Boshen <1430279+Boshen@users.noreply.github.com> Date: Fri, 3 Jan 2025 12:24:57 +0000 Subject: [PATCH] feat(minifier): remove last redundant `return` statement (#8234) --- .../src/ast_passes/minimize_exit_points.rs | 25 +++++++++++++++++++ crates/oxc_minifier/src/ast_passes/mod.rs | 4 +++ tasks/minsize/minsize.snap | 12 ++++----- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs b/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs index 3792787f51c08..600587a31c011 100644 --- a/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs +++ b/crates/oxc_minifier/src/ast_passes/minimize_exit_points.rs @@ -22,6 +22,10 @@ impl<'a> CompressorPass<'a> for MinimizeExitPoints { } impl<'a> Traverse<'a> for MinimizeExitPoints { + fn exit_function_body(&mut self, body: &mut FunctionBody<'a>, _ctx: &mut TraverseCtx<'a>) { + self.remove_last_return(&mut body.statements); + } + fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { self.fold_if_return(stmts, ctx); } @@ -32,6 +36,16 @@ impl<'a> MinimizeExitPoints { Self { changed: false } } + // `function foo() { return }` -> `function foo() {}` + fn remove_last_return(&mut self, stmts: &mut Vec<'a, Statement<'a>>) { + if let Some(last) = stmts.last() { + if matches!(last, Statement::ReturnStatement(ret) if ret.argument.is_none()) { + stmts.pop(); + self.changed = true; + } + } + } + // `if(x)return;foo` -> `if(!x)foo;` fn fold_if_return(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) { if stmts.len() <= 1 { @@ -87,6 +101,8 @@ mod test { fold(source_text, source_text); } + // oxc + #[test] fn simple() { fold( @@ -109,6 +125,15 @@ mod test { fold_same("function foo() { if (foo) return bar; baz }"); } + #[test] + fn remove_last_return() { + fold("function () {return}", "function () {}"); + fold("function () {a;b;return}", "function () {a;b;}"); + fold_same("function () { if(foo) { return } }"); + } + + // closure + #[test] #[ignore] fn test_break_optimization() { diff --git a/crates/oxc_minifier/src/ast_passes/mod.rs b/crates/oxc_minifier/src/ast_passes/mod.rs index fae87b8437b32..50bce420fae90 100644 --- a/crates/oxc_minifier/src/ast_passes/mod.rs +++ b/crates/oxc_minifier/src/ast_passes/mod.rs @@ -141,6 +141,10 @@ impl<'a> Traverse<'a> for PeepholeOptimizations { self.x6_peephole_substitute_alternate_syntax.exit_return_statement(stmt, ctx); } + fn exit_function_body(&mut self, body: &mut FunctionBody<'a>, ctx: &mut TraverseCtx<'a>) { + self.x1_minimize_exit_points.exit_function_body(body, ctx); + } + fn exit_variable_declaration( &mut self, decl: &mut VariableDeclaration<'a>, diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index b8cc4fc06c5a6..5ef32c59a39dc 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -1,7 +1,7 @@ | Oxc | ESBuild | Oxc | ESBuild | Original | minified | minified | gzip | gzip | Fixture ------------------------------------------------------------------------------------- -72.14 kB | 23.69 kB | 23.70 kB | 8.62 kB | 8.54 kB | react.development.js +72.14 kB | 23.68 kB | 23.70 kB | 8.61 kB | 8.54 kB | react.development.js 173.90 kB | 59.86 kB | 59.82 kB | 19.43 kB | 19.33 kB | moment.js @@ -15,13 +15,13 @@ Original | minified | minified | gzip | gzip | Fixture 1.01 MB | 460.32 kB | 458.89 kB | 126.85 kB | 126.71 kB | bundle.min.js -1.25 MB | 652.73 kB | 646.76 kB | 163.54 kB | 163.73 kB | three.js +1.25 MB | 652.68 kB | 646.76 kB | 163.53 kB | 163.73 kB | three.js -2.14 MB | 726.33 kB | 724.14 kB | 180.20 kB | 181.07 kB | victory.js +2.14 MB | 726.19 kB | 724.14 kB | 180.18 kB | 181.07 kB | victory.js -3.20 MB | 1.01 MB | 1.01 MB | 331.92 kB | 331.56 kB | echarts.js +3.20 MB | 1.01 MB | 1.01 MB | 331.91 kB | 331.56 kB | echarts.js -6.69 MB | 2.32 MB | 2.31 MB | 492.82 kB | 488.28 kB | antd.js +6.69 MB | 2.32 MB | 2.31 MB | 492.81 kB | 488.28 kB | antd.js -10.95 MB | 3.50 MB | 3.49 MB | 909.58 kB | 915.50 kB | typescript.js +10.95 MB | 3.50 MB | 3.49 MB | 909.31 kB | 915.50 kB | typescript.js