From 8fb71f518fbe4c1936f098725f0cb685dbb3dd0e Mon Sep 17 00:00:00 2001 From: Boshen <1430279+Boshen@users.noreply.github.com> Date: Fri, 27 Dec 2024 15:09:41 +0000 Subject: [PATCH] feat(minifier): minify string `PropertyKey` (#8147) --- crates/oxc_minifier/src/ast_passes/mod.rs | 4 ++ .../peephole_substitute_alternate_syntax.rs | 43 +++++++++++++++++++ tasks/minsize/minsize.snap | 18 ++++---- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/crates/oxc_minifier/src/ast_passes/mod.rs b/crates/oxc_minifier/src/ast_passes/mod.rs index d92458fd6724d..459265a14fe03 100644 --- a/crates/oxc_minifier/src/ast_passes/mod.rs +++ b/crates/oxc_minifier/src/ast_passes/mod.rs @@ -190,6 +190,10 @@ impl<'a> Traverse<'a> for LatePeepholeOptimizations { fn exit_call_expression(&mut self, expr: &mut CallExpression<'a>, ctx: &mut TraverseCtx<'a>) { self.x4_peephole_substitute_alternate_syntax.exit_call_expression(expr, ctx); } + + 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); + } } // See `createPeepholeOptimizationsPass` 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 692b2b06517ba..83ddc1af628a6 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 @@ -77,6 +77,10 @@ impl<'a> Traverse<'a> for PeepholeSubstituteAlternateSyntax { self.in_define_export = false; } + fn exit_property_key(&mut self, key: &mut PropertyKey<'a>, ctx: &mut TraverseCtx<'a>) { + self.try_compress_property_key(key, ctx); + } + fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { let ctx = Ctx(ctx); @@ -687,6 +691,39 @@ impl<'a, 'b> PeepholeSubstituteAlternateSyntax { fn empty_array_literal(ctx: Ctx<'a, 'b>) -> Expression<'a> { Self::array_literal(ctx.ast.vec(), ctx) } + + // https://github.com/swc-project/swc/blob/4e2dae558f60a9f5c6d2eac860743e6c0b2ec562/crates/swc_ecma_minifier/src/compress/pure/properties.rs + #[allow(clippy::cast_lossless)] + fn try_compress_property_key(&mut self, key: &mut PropertyKey<'a>, ctx: &mut TraverseCtx<'a>) { + use oxc_syntax::identifier::is_identifier_name; + let PropertyKey::StringLiteral(s) = key else { return }; + if match ctx.parent() { + Ancestor::ObjectPropertyKey(key) => *key.computed(), + Ancestor::BindingPropertyKey(key) => *key.computed(), + Ancestor::MethodDefinitionKey(key) => *key.computed(), + Ancestor::PropertyDefinitionKey(key) => *key.computed(), + Ancestor::AccessorPropertyKey(key) => *key.computed(), + _ => true, + } { + return; + } + if is_identifier_name(&s.value) { + self.changed = true; + *key = PropertyKey::StaticIdentifier( + ctx.ast.alloc_identifier_name(s.span, s.value.clone()), + ); + } else if (!s.value.starts_with('0') && !s.value.starts_with('+')) || s.value.len() <= 1 { + if let Ok(value) = s.value.parse::() { + self.changed = true; + *key = PropertyKey::NumericLiteral(ctx.ast.alloc_numeric_literal( + s.span, + value as f64, + None, + NumberBase::Decimal, + )); + } + } + } } /// Port from @@ -1137,4 +1174,10 @@ mod test { test("typeof foo !== `number`", "typeof foo != 'number'"); test("`number` !== typeof foo", "'number' != typeof foo"); } + + #[test] + fn test_object_key() { + test("({ '0': _, 'a': _ })", "({ 0: _, a: _ })"); + test_same("({ '1.1': _, '😊': _, 'a.a': _ })"); + } } diff --git a/tasks/minsize/minsize.snap b/tasks/minsize/minsize.snap index df2d1af01df2b..8bb240402d3bf 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.22 kB | 59.82 kB | 19.49 kB | 19.33 kB | moment.js -287.63 kB | 90.74 kB | 90.07 kB | 32.21 kB | 31.95 kB | jquery.js +287.63 kB | 90.61 kB | 90.07 kB | 32.19 kB | 31.95 kB | jquery.js -342.15 kB | 118.77 kB | 118.14 kB | 44.54 kB | 44.37 kB | vue.js +342.15 kB | 118.76 kB | 118.14 kB | 44.54 kB | 44.37 kB | vue.js -544.10 kB | 72.53 kB | 72.48 kB | 26.23 kB | 26.20 kB | lodash.js +544.10 kB | 72.05 kB | 72.48 kB | 26.19 kB | 26.20 kB | lodash.js -555.77 kB | 274.26 kB | 270.13 kB | 91.26 kB | 90.80 kB | d3.js +555.77 kB | 274.04 kB | 270.13 kB | 91.20 kB | 90.80 kB | d3.js 1.01 MB | 461.13 kB | 458.89 kB | 126.91 kB | 126.71 kB | bundle.min.js -1.25 MB | 657.23 kB | 646.76 kB | 164.23 kB | 163.73 kB | three.js +1.25 MB | 656.86 kB | 646.76 kB | 164.20 kB | 163.73 kB | three.js -2.14 MB | 735.67 kB | 724.14 kB | 181.09 kB | 181.07 kB | victory.js +2.14 MB | 735.43 kB | 724.14 kB | 181.01 kB | 181.07 kB | victory.js -3.20 MB | 1.01 MB | 1.01 MB | 332.35 kB | 331.56 kB | echarts.js +3.20 MB | 1.01 MB | 1.01 MB | 332.34 kB | 331.56 kB | echarts.js -6.69 MB | 2.38 MB | 2.31 MB | 495.33 kB | 488.28 kB | antd.js +6.69 MB | 2.36 MB | 2.31 MB | 495.04 kB | 488.28 kB | antd.js -10.95 MB | 3.51 MB | 3.49 MB | 910.94 kB | 915.50 kB | typescript.js +10.95 MB | 3.51 MB | 3.49 MB | 910.95 kB | 915.50 kB | typescript.js