diff --git a/crates/oxc_minifier/src/ast_passes/mod.rs b/crates/oxc_minifier/src/ast_passes/mod.rs index 459265a14fe03..e4b19d8a20f05 100644 --- a/crates/oxc_minifier/src/ast_passes/mod.rs +++ b/crates/oxc_minifier/src/ast_passes/mod.rs @@ -194,6 +194,14 @@ impl<'a> Traverse<'a> for LatePeepholeOptimizations { fn exit_property_key(&mut self, key: &mut PropertyKey<'a>, ctx: &mut TraverseCtx<'a>) { self.x4_peephole_substitute_alternate_syntax.exit_property_key(key, ctx); } + + fn exit_member_expression( + &mut self, + expr: &mut MemberExpression<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.x4_peephole_substitute_alternate_syntax.exit_member_expression(expr, ctx); + } } // See `createPeepholeOptimizationsPass` @@ -269,6 +277,14 @@ impl<'a> Traverse<'a> for PeepholeOptimizations { fn exit_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) { self.x3_peephole_substitute_alternate_syntax.exit_call_expression(expr, ctx); } + + fn exit_member_expression( + &mut self, + expr: &mut MemberExpression<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.x3_peephole_substitute_alternate_syntax.exit_member_expression(expr, ctx); + } } pub struct DeadCodeElimination { diff --git a/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs b/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs index 2693cb60876fa..b2c2e211f7434 100644 --- a/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs +++ b/crates/oxc_minifier/src/ast_passes/peephole_substitute_alternate_syntax.rs @@ -82,6 +82,16 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax { self.try_compress_property_key(key, ctx); } + fn exit_member_expression( + &mut self, + expr: &mut MemberExpression<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + let ctx = Ctx(ctx); + + self.try_compress_computed_member_expression(expr, ctx); + } + fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { let ctx = Ctx(ctx); @@ -102,9 +112,6 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax { Expression::NewExpression(e) => Self::try_fold_new_expression(e, ctx), Expression::TemplateLiteral(t) => Self::try_fold_template_literal(t, ctx), Expression::BinaryExpression(e) => Self::try_compress_typeof_undefined(e, ctx), - Expression::ComputedMemberExpression(e) => { - self.try_compress_computed_member_expression(e, ctx) - } Expression::CallExpression(e) => { Self::try_fold_literal_constructor_call_expression(e, ctx) .or_else(|| Self::try_fold_simple_function_call(e, ctx)) @@ -749,23 +756,28 @@ impl<'a, 'b> PeepholeSubstituteAlternateSyntax { } /// `foo['bar']` -> `foo.bar` + /// `foo?.['bar']` -> `foo?.bar` fn try_compress_computed_member_expression( - &self, - e: &mut ComputedMemberExpression<'a>, + &mut self, + expr: &mut MemberExpression<'a>, ctx: Ctx<'a, 'b>, - ) -> Option> { + ) { if self.in_fixed_loop { - return None; + return; } - let Expression::StringLiteral(s) = &e.expression else { return None }; - if !is_identifier_name(&s.value) { - return None; + + if let MemberExpression::ComputedMemberExpression(e) = expr { + let Expression::StringLiteral(s) = &e.expression else { return }; + if !is_identifier_name(&s.value) { + return; + } + let property = ctx.ast.identifier_name(s.span, s.value.clone()); + let object = ctx.ast.move_expression(&mut e.object); + *expr = MemberExpression::StaticMemberExpression( + ctx.ast.alloc_static_member_expression(e.span, object, property, e.optional), + ); + self.changed = true; } - let property = ctx.ast.identifier_name(s.span, s.value.clone()); - let object = ctx.ast.move_expression(&mut e.object); - Some(Expression::StaticMemberExpression( - ctx.ast.alloc_static_member_expression(e.span, object, property, false), - )) } } @@ -1335,7 +1347,6 @@ mod test { } #[test] - #[ignore] fn test_convert_to_dotted_properties_optional_chaining() { test("data?.['name']", "data?.name"); test("data?.['name']?.['first']", "data?.name?.first"); @@ -1460,7 +1471,6 @@ mod test { } #[test] - #[ignore] fn test_convert_to_dotted_properties_continue_optional_chaining() { test("const opt1 = window?.a?.['b'];", "const opt1 = window?.a?.b;"); diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index 4a350420714eb..e9b4ae5f257d7 100644 --- a/tasks/minsize/minsize.snap +++ b/tasks/minsize/minsize.snap @@ -5,23 +5,23 @@ Original | minified | minified | gzip | gzip | Fixture 173.90 kB | 60.16 kB | 59.82 kB | 19.48 kB | 19.33 kB | moment.js -287.63 kB | 90.70 kB | 90.07 kB | 32.21 kB | 31.95 kB | jquery.js +287.63 kB | 90.68 kB | 90.07 kB | 32.20 kB | 31.95 kB | jquery.js 342.15 kB | 118.59 kB | 118.14 kB | 44.53 kB | 44.37 kB | vue.js -544.10 kB | 72.49 kB | 72.48 kB | 26.22 kB | 26.20 kB | lodash.js +544.10 kB | 72.48 kB | 72.48 kB | 26.21 kB | 26.20 kB | lodash.js 555.77 kB | 274.10 kB | 270.13 kB | 91.25 kB | 90.80 kB | d3.js -1.01 MB | 461.06 kB | 458.89 kB | 126.91 kB | 126.71 kB | bundle.min.js +1.01 MB | 461.05 kB | 458.89 kB | 126.89 kB | 126.71 kB | bundle.min.js 1.25 MB | 656.99 kB | 646.76 kB | 164.18 kB | 163.73 kB | three.js -2.14 MB | 728.22 kB | 724.14 kB | 180.43 kB | 181.07 kB | victory.js +2.14 MB | 727.49 kB | 724.14 kB | 180.39 kB | 181.07 kB | victory.js 3.20 MB | 1.01 MB | 1.01 MB | 332.24 kB | 331.56 kB | echarts.js -6.69 MB | 2.34 MB | 2.31 MB | 493.51 kB | 488.28 kB | antd.js +6.69 MB | 2.34 MB | 2.31 MB | 493.37 kB | 488.28 kB | antd.js -10.95 MB | 3.51 MB | 3.49 MB | 910.88 kB | 915.50 kB | typescript.js +10.95 MB | 3.51 MB | 3.49 MB | 910.43 kB | 915.50 kB | typescript.js