diff --git a/crates/oxc_minifier/src/peephole/minimize_statements.rs b/crates/oxc_minifier/src/peephole/minimize_statements.rs index bab4e9fdfa451..d7c731898d9ca 100644 --- a/crates/oxc_minifier/src/peephole/minimize_statements.rs +++ b/crates/oxc_minifier/src/peephole/minimize_statements.rs @@ -374,11 +374,21 @@ impl<'a> PeepholeOptimizations { /// * remove the variable declarator if it is unused /// * keep the initializer if it has side effects fn handle_variable_declaration( - var_decl: Box<'a, VariableDeclaration<'a>>, + mut var_decl: Box<'a, VariableDeclaration<'a>>, result: &mut Vec<'a, Statement<'a>>, ctx: &mut Ctx<'a, '_>, ) { + if let Some(first_decl) = var_decl.declarations.first_mut() + && let Some(first_decl_init) = first_decl.init.as_mut() + { + let changed = + Self::substitute_single_use_symbol_in_statement(first_decl_init, result, ctx); + if changed { + ctx.state.changed = true; + } + } + // If `join_vars` is off, but there are unused declarators ... just join them to make our code simpler. if !ctx.options().join_vars && var_decl.declarations.iter().all(|d| !Self::should_remove_unused_declarator(d, ctx)) @@ -421,6 +431,12 @@ impl<'a> PeepholeOptimizations { ctx: &mut Ctx<'a, '_>, ) { + let changed = + Self::substitute_single_use_symbol_in_statement(&mut expr_stmt.expression, result, ctx); + if changed { + ctx.state.changed = true; + } + if ctx.options().sequences { if let Some(Statement::ExpressionStatement(prev_expr_stmt)) = result.last_mut() { let a = &mut prev_expr_stmt.expression; @@ -439,6 +455,15 @@ impl<'a> PeepholeOptimizations { ctx: &mut Ctx<'a, '_>, ) { + let changed = Self::substitute_single_use_symbol_in_statement( + &mut switch_stmt.discriminant, + result, + ctx, + ); + if changed { + ctx.state.changed = true; + } + if ctx.options().sequences { if let Some(Statement::ExpressionStatement(prev_expr_stmt)) = result.last_mut() { let a = &mut prev_expr_stmt.expression; @@ -460,6 +485,12 @@ impl<'a> PeepholeOptimizations { ctx: &mut Ctx<'a, '_>, ) -> ControlFlow<()> { + let changed = + Self::substitute_single_use_symbol_in_statement(&mut if_stmt.test, result, ctx); + if changed { + ctx.state.changed = true; + } + // Absorb a previous expression statement if ctx.options().sequences { if let Some(Statement::ExpressionStatement(prev_expr_stmt)) = result.last_mut() { @@ -666,6 +697,12 @@ impl<'a> PeepholeOptimizations { ctx: &mut Ctx<'a, '_>, ) { + let changed = + Self::substitute_single_use_symbol_in_statement(&mut throw_stmt.argument, result, ctx); + if changed { + ctx.state.changed = true; + } + if ctx.options().sequences { if let Some(Statement::ExpressionStatement(prev_expr_stmt)) = result.last_mut() { let a = &mut prev_expr_stmt.expression; diff --git a/crates/oxc_minifier/tests/peephole/esbuild.rs b/crates/oxc_minifier/tests/peephole/esbuild.rs index 37188be04e37f..e2977c711adc6 100644 --- a/crates/oxc_minifier/tests/peephole/esbuild.rs +++ b/crates/oxc_minifier/tests/peephole/esbuild.rs @@ -1957,14 +1957,14 @@ fn test_inline_single_use_variable() { "function wrapper(arg0, arg1) { let x = fn(); return arg0 ?? x;}", "function wrapper(arg0, arg1) { let x = fn(); return arg0 ?? x;}", ); - // test( - // "function wrapper(arg0, arg1) { let x = fn(); let y = x[prop]; let z = y.val; throw z}", - // "function wrapper(arg0, arg1) { throw fn()[prop].val;}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = fn(), y = x[prop], z = y.val; throw z}", - // "function wrapper(arg0, arg1) { throw fn()[prop].val;}", - // ); + test( + "function wrapper(arg0, arg1) { let x = fn(); let y = x[prop]; let z = y.val; throw z}", + "function wrapper(arg0, arg1) { throw fn()[prop].val;}", + ); + test( + "function wrapper(arg0, arg1) { let x = fn(), y = x[prop], z = y.val; throw z}", + "function wrapper(arg0, arg1) { throw fn()[prop].val;}", + ); test( "function wrapper(arg0, arg1) { let x = fn(); let y = x[prop]; let z = y.val; return z}", "function wrapper(arg0, arg1) { return fn()[prop].val;}", @@ -2014,42 +2014,42 @@ fn test_inline_single_use_variable() { "function wrapper(arg0, arg1) { let x = arg0; return arg1(...arg1, x);}", "function wrapper(arg0, arg1) { let x = arg0; return arg1(...arg1, x);}", ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0; arg1(x);}", - // "function wrapper(arg0, arg1) { arg1(arg0);}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0; throw x;}", - // "function wrapper(arg0, arg1) { throw arg0;}", - // ); + test( + "function wrapper(arg0, arg1) { let x = arg0; arg1(x);}", + "function wrapper(arg0, arg1) { arg1(arg0);}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0; throw x;}", + "function wrapper(arg0, arg1) { throw arg0;}", + ); test( "function wrapper(arg0, arg1) { let x = arg0; return x;}", "function wrapper(arg0, arg1) { return arg0;}", ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0; if (x) return 1;}", - // "function wrapper(arg0, arg1) { if (arg0) return 1;}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0; switch (x) { case 0: return 1; }}", - // "function wrapper(arg0, arg1) { switch (arg0) { case 0: return 1; }}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0; let y = x; return y + y;}", - // "function wrapper(arg0, arg1) { let y = arg0; return y + y;}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0; do {} while (x);}", - // "function wrapper(arg0, arg1) { let x = arg0; do ; while (x);}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0; while (x) return 1;}", - // "function wrapper(arg0, arg1) { let x = arg0; for (; x; ) return 1;}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0; for (; x; ) return 1;}", - // "function wrapper(arg0, arg1) { let x = arg0; for (; x; ) return 1;}", - // ); + test( + "function wrapper(arg0, arg1) { let x = arg0; if (x) return 1;}", + "function wrapper(arg0, arg1) { if (arg0) return 1;}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0; switch (x) { case 0: return 1; }}", + "function wrapper(arg0, arg1) { switch (arg0) { case 0: return 1; }}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0; let y = x; return y + y;}", + "function wrapper(arg0, arg1) { let y = arg0; return y + y;}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0; do {} while (x);}", + "function wrapper(arg0, arg1) { let x = arg0; do ; while (x);}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0; while (x) return 1;}", + "function wrapper(arg0, arg1) { let x = arg0; for (; x; ) return 1;}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0; for (; x; ) return 1;}", + "function wrapper(arg0, arg1) { let x = arg0; for (; x; ) return 1;}", + ); test( "function wrapper(arg0, arg1) { let x = arg0; return arg1?.[x];}", "function wrapper(arg0, arg1) { return arg1?.[arg0];}", @@ -2186,10 +2186,10 @@ fn test_inline_single_use_variable() { "function wrapper(arg0, arg1) { let x = arg0; return [import(arg1), x];}", "function wrapper(arg0, arg1) { return [import(arg1), arg0];}", ); - // test( - // "function wrapper(arg0, arg1) {return async () => { let x = arg0; await x; };}", - // "function wrapper(arg0, arg1) { return async () => { await arg0; };}", - // ); + test( + "function wrapper(arg0, arg1) {return async () => { let x = arg0; await x; };}", + "function wrapper(arg0, arg1) { return async () => { await arg0; };}", + ); test( "function wrapper(arg0, arg1) {return async () => { let x = arg0; await y; return x; };}", "function wrapper(arg0, arg1) { return async () => { let x = arg0; return await y, x; };}", @@ -2198,10 +2198,10 @@ fn test_inline_single_use_variable() { "function wrapper(arg0, arg1) {return async () => { let x = arg0; await arg1; return x; };}", "function wrapper(arg0, arg1) { return async () => { let x = arg0; return await arg1, x; };}", ); - // test( - // "function wrapper(arg0, arg1) {return function* () { let x = arg0; yield x; };}", - // "function wrapper(arg0, arg1) { return function* () { yield arg0; };}", - // ); + test( + "function wrapper(arg0, arg1) {return function* () { let x = arg0; yield x; };}", + "function wrapper(arg0, arg1) { return function* () { yield arg0; };}", + ); test( "function wrapper(arg0, arg1) {return function* () { let x = arg0; yield; return x; };}", "function wrapper(arg0, arg1) { return function* () { let x = arg0; return yield, x; };}", @@ -2214,70 +2214,70 @@ fn test_inline_single_use_variable() { "function wrapper(arg0, arg1) {return function* () { let x = arg0; yield arg1; return x; };}", "function wrapper(arg0, arg1) { return function* () { let x = arg0; return yield arg1, x; };}", ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0; x()}", - // "function wrapper(arg0, arg1) { arg0();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0; (0, x)()}", - // "function wrapper(arg0, arg1) { arg0();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0.foo; x.bar()}", - // "function wrapper(arg0, arg1) { arg0.foo.bar();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0.foo; x[bar]()}", - // "function wrapper(arg0, arg1) { arg0.foo[bar]();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0.foo; x()}", - // "function wrapper(arg0, arg1) { let x = arg0.foo; x();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0[foo]; x()}", - // "function wrapper(arg0, arg1) { let x = arg0[foo]; x();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0?.foo; x()}", - // "function wrapper(arg0, arg1) { let x = arg0?.foo; x();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0?.[foo]; x()}", - // "function wrapper(arg0, arg1) { let x = arg0?.[foo]; x();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0.foo; (0, x)()}", - // "function wrapper(arg0, arg1) { let x = arg0.foo; x();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0[foo]; (0, x)()}", - // "function wrapper(arg0, arg1) { let x = arg0[foo]; x();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0?.foo; (0, x)()}", - // "function wrapper(arg0, arg1) { let x = arg0?.foo; x();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0?.[foo]; (0, x)()}", - // "function wrapper(arg0, arg1) { let x = arg0?.[foo]; x();}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0(); arg1() + x}", - // "function wrapper(arg0, arg1) { let x = arg0(); arg1() + x;}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = arg0(); /* @__PURE__ */ arg1() + x}", - // "function wrapper(arg0, arg1) { let x = arg0(); /* @__PURE__ */ arg1() + x;}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = /* @__PURE__ */ arg0(); arg1() + x}", - // "function wrapper(arg0, arg1) { let x = /* @__PURE__ */ arg0(); arg1() + x;}", - // ); - // test( - // "function wrapper(arg0, arg1) { let x = /* @__PURE__ */ arg0(); /* @__PURE__ */ arg1() + x}", - // "function wrapper(arg0, arg1) { /* @__PURE__ */ arg1() + /* @__PURE__ */ arg0();}", - // ); + test( + "function wrapper(arg0, arg1) { let x = arg0; x()}", + "function wrapper(arg0, arg1) { arg0();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0; (0, x)()}", + "function wrapper(arg0, arg1) { arg0();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0.foo; x.bar()}", + "function wrapper(arg0, arg1) { arg0.foo.bar();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0.foo; x[bar]()}", + "function wrapper(arg0, arg1) { arg0.foo[bar]();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0.foo; x()}", + "function wrapper(arg0, arg1) { let x = arg0.foo; x();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0[foo]; x()}", + "function wrapper(arg0, arg1) { let x = arg0[foo]; x();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0?.foo; x()}", + "function wrapper(arg0, arg1) { let x = arg0?.foo; x();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0?.[foo]; x()}", + "function wrapper(arg0, arg1) { let x = arg0?.[foo]; x();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0.foo; (0, x)()}", + "function wrapper(arg0, arg1) { let x = arg0.foo; x();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0[foo]; (0, x)()}", + "function wrapper(arg0, arg1) { let x = arg0[foo]; x();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0?.foo; (0, x)()}", + "function wrapper(arg0, arg1) { let x = arg0?.foo; x();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0?.[foo]; (0, x)()}", + "function wrapper(arg0, arg1) { let x = arg0?.[foo]; x();}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0(); arg1() + x}", + "function wrapper(arg0, arg1) { let x = arg0(); arg1() + x;}", + ); + test( + "function wrapper(arg0, arg1) { let x = arg0(); /* @__PURE__ */ arg1() + x}", + "function wrapper(arg0, arg1) { let x = arg0(); /* @__PURE__ */ arg1() + x;}", + ); + test( + "function wrapper(arg0, arg1) { let x = /* @__PURE__ */ arg0(); arg1() + x}", + "function wrapper(arg0, arg1) { let x = /* @__PURE__ */ arg0(); arg1() + x;}", + ); + test( + "function wrapper(arg0, arg1) { let x = /* @__PURE__ */ arg0(); /* @__PURE__ */ arg1() + x}", + "function wrapper(arg0, arg1) { /* @__PURE__ */ arg1() + /* @__PURE__ */ arg0();}", + ); } #[test] diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index da4e2eff0a16f..3a62a846b922a 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -1,27 +1,27 @@ | Oxc | ESBuild | Oxc | ESBuild | Original | minified | minified | gzip | gzip | Iterations | File ------------------------------------------------------------------------------------- -72.14 kB | 23.23 kB | 23.70 kB | 8.40 kB | 8.54 kB | 2 | react.development.js +72.14 kB | 23.22 kB | 23.70 kB | 8.39 kB | 8.54 kB | 2 | react.development.js 173.90 kB | 59.47 kB | 59.82 kB | 19.18 kB | 19.33 kB | 2 | moment.js -287.63 kB | 89.31 kB | 90.07 kB | 30.95 kB | 31.95 kB | 2 | jquery.js +287.63 kB | 89.29 kB | 90.07 kB | 30.95 kB | 31.95 kB | 2 | jquery.js -342.15 kB | 117.17 kB | 118.14 kB | 43.27 kB | 44.37 kB | 2 | vue.js +342.15 kB | 117.02 kB | 118.14 kB | 43.19 kB | 44.37 kB | 2 | vue.js -544.10 kB | 71.20 kB | 72.48 kB | 25.85 kB | 26.20 kB | 3 | lodash.js +544.10 kB | 71.18 kB | 72.48 kB | 25.85 kB | 26.20 kB | 2 | lodash.js -555.77 kB | 270.85 kB | 270.13 kB | 88.23 kB | 90.80 kB | 2 | d3.js +555.77 kB | 270.81 kB | 270.13 kB | 88.21 kB | 90.80 kB | 2 | d3.js -1.01 MB | 439.88 kB | 458.89 kB | 122.24 kB | 126.71 kB | 3 | bundle.min.js +1.01 MB | 439.64 kB | 458.89 kB | 122.16 kB | 126.71 kB | 2 | bundle.min.js -1.25 MB | 646.86 kB | 646.76 kB | 160.24 kB | 163.73 kB | 2 | three.js +1.25 MB | 645.80 kB | 646.76 kB | 159.59 kB | 163.73 kB | 2 | three.js -2.14 MB | 714.65 kB | 724.14 kB | 161.41 kB | 181.07 kB | 2 | victory.js +2.14 MB | 714.13 kB | 724.14 kB | 161.16 kB | 181.07 kB | 2 | victory.js -3.20 MB | 1.01 MB | 1.01 MB | 323.86 kB | 331.56 kB | 3 | echarts.js +3.20 MB | 1.00 MB | 1.01 MB | 323.35 kB | 331.56 kB | 3 | echarts.js -6.69 MB | 2.23 MB | 2.31 MB | 460.69 kB | 488.28 kB | 4 | antd.js +6.69 MB | 2.23 MB | 2.31 MB | 460.30 kB | 488.28 kB | 4 | antd.js -10.95 MB | 3.34 MB | 3.49 MB | 856.46 kB | 915.50 kB | 4 | typescript.js +10.95 MB | 3.34 MB | 3.49 MB | 855.59 kB | 915.50 kB | 4 | typescript.js