From 95761b76bf09a4d2c09517b2bd7bf7b78ee2149f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Wed, 13 Mar 2024 11:21:15 +0900 Subject: [PATCH] fix(es/minifier): Make `Finalizer` handle `hoisted_props` correctly (#8738) **Related issue:** - Closes #8737 --- .../fixture/issues-8xxx/8737/input/.swcrc | 63 +++++++++++++++++++ .../tests/fixture/issues-8xxx/8737/input/1.js | 14 +++++ .../fixture/issues-8xxx/8737/output/1.js | 8 +++ .../src/compress/optimize/mod.rs | 1 + .../src/compress/optimize/util.rs | 33 ++++++---- .../tests/fixture/issues/8737/2/input.js | 10 +++ .../tests/fixture/issues/8737/2/output.js | 8 +++ .../tests/fixture/issues/8737/config.json | 47 ++++++++++++++ .../tests/fixture/issues/8737/input.js | 14 +++++ .../tests/fixture/issues/8737/output.js | 6 ++ 10 files changed, 193 insertions(+), 11 deletions(-) create mode 100644 crates/swc/tests/fixture/issues-8xxx/8737/input/.swcrc create mode 100644 crates/swc/tests/fixture/issues-8xxx/8737/input/1.js create mode 100644 crates/swc/tests/fixture/issues-8xxx/8737/output/1.js create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/8737/2/input.js create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/8737/2/output.js create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/8737/config.json create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/8737/input.js create mode 100644 crates/swc_ecma_minifier/tests/fixture/issues/8737/output.js diff --git a/crates/swc/tests/fixture/issues-8xxx/8737/input/.swcrc b/crates/swc/tests/fixture/issues-8xxx/8737/input/.swcrc new file mode 100644 index 000000000000..cd530500a1f2 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8737/input/.swcrc @@ -0,0 +1,63 @@ +{ + "jsc": { + "parser": { + "syntax": "ecmascript", + "jsx": false + }, + "target": "es5", + "loose": false, + "minify": { + "compress": { + "arguments": false, + "arrows": true, + "booleans": true, + "booleans_as_integers": false, + "collapse_vars": true, + "comparisons": true, + "computed_props": true, + "conditionals": true, + "dead_code": true, + "directives": true, + "drop_console": false, + "drop_debugger": true, + "evaluate": true, + "expression": false, + "hoist_funs": false, + "hoist_props": true, + "hoist_vars": false, + "if_return": true, + "join_vars": true, + "keep_classnames": false, + "keep_fargs": true, + "keep_fnames": false, + "keep_infinity": false, + "loops": true, + "negate_iife": true, + "properties": true, + "reduce_funcs": false, + "reduce_vars": false, + "side_effects": true, + "switches": true, + "typeofs": true, + "unsafe": false, + "unsafe_arrows": false, + "unsafe_comps": false, + "unsafe_Function": false, + "unsafe_math": false, + "unsafe_symbols": false, + "unsafe_methods": false, + "unsafe_proto": false, + "unsafe_regexp": false, + "unsafe_undefined": false, + "unused": true, + "const_to_let": true, + "pristine_globals": true + }, + "mangle": false + } + }, + "module": { + "type": "es6" + }, + "isModule": true +} \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-8xxx/8737/input/1.js b/crates/swc/tests/fixture/issues-8xxx/8737/input/1.js new file mode 100644 index 000000000000..c77842050387 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8737/input/1.js @@ -0,0 +1,14 @@ +d(() => { + var obj = { + key: "some string", + }; + + var b = () => { + switch (a) { + default: + break; + } + return obj.key; + }; + return () => b; +}); \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-8xxx/8737/output/1.js b/crates/swc/tests/fixture/issues-8xxx/8737/output/1.js new file mode 100644 index 000000000000..bb0fd3bbeaa5 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8737/output/1.js @@ -0,0 +1,8 @@ +d(function() { + var b = function() { + return a, "some string"; + }; + return function() { + return b; + }; +}); diff --git a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs index f9e1a7146916..770d14ecf4e5 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs @@ -269,6 +269,7 @@ impl Vars { || !self.lits.is_empty() || !self.lits_for_cmp.is_empty() || !self.lits_for_array_access.is_empty() + || !self.hoisted_props.is_empty() || !self.removed.is_empty() { let mut v = Finalizer { diff --git a/crates/swc_ecma_minifier/src/compress/optimize/util.rs b/crates/swc_ecma_minifier/src/compress/optimize/util.rs index ab671c14a532..7ae6087aeae3 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/util.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/util.rs @@ -405,24 +405,35 @@ impl VisitMut for Finalizer<'_> { } fn visit_mut_expr(&mut self, n: &mut Expr) { - if let Expr::Ident(i) = n { - if let Some(expr) = self.lits.get(&i.to_id()) { - *n = *expr.clone(); + match n { + Expr::Ident(i) => { + if let Some(expr) = self.lits.get(&i.to_id()) { + *n = *expr.clone(); + return; + } } - } else { - n.visit_mut_children_with(self); - } - - if let Expr::Member(e) = n { - if let Expr::Ident(obj) = &*e.obj { - if let MemberProp::Ident(prop) = &e.prop { - if let Some(ident) = self.hoisted_props.get(&(obj.to_id(), prop.sym.clone())) { + Expr::Member(e) => { + if let Expr::Ident(obj) = &*e.obj { + let sym = match &e.prop { + MemberProp::Ident(i) => &i.sym, + MemberProp::Computed(e) => match &*e.expr { + Expr::Lit(Lit::Str(s)) => &s.value, + _ => return, + }, + _ => return, + }; + + if let Some(ident) = self.hoisted_props.get(&(obj.to_id(), sym.clone())) { self.changed = true; *n = ident.clone().into(); + return; } } } + _ => {} } + + n.visit_mut_children_with(self); } fn visit_mut_stmts(&mut self, n: &mut Vec) { diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/8737/2/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/8737/2/input.js new file mode 100644 index 000000000000..bbca9b5721ca --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/8737/2/input.js @@ -0,0 +1,10 @@ +d(function () { + var obj = { + key: "some string" + }, b = function () { + return a, obj.key; + }; + return function () { + return b; + }; +}); diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/8737/2/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/8737/2/output.js new file mode 100644 index 000000000000..bb0fd3bbeaa5 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/8737/2/output.js @@ -0,0 +1,8 @@ +d(function() { + var b = function() { + return a, "some string"; + }; + return function() { + return b; + }; +}); diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/8737/config.json b/crates/swc_ecma_minifier/tests/fixture/issues/8737/config.json new file mode 100644 index 000000000000..7e144b291fa7 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/8737/config.json @@ -0,0 +1,47 @@ +{ + "defaults": true, + "arguments": false, + "arrows": true, + "booleans": true, + "booleans_as_integers": false, + "collapse_vars": true, + "comparisons": true, + "computed_props": true, + "conditionals": true, + "dead_code": true, + "directives": true, + "drop_console": false, + "drop_debugger": true, + "evaluate": true, + "expression": false, + "hoist_funs": false, + "hoist_props": true, + "hoist_vars": false, + "if_return": true, + "join_vars": true, + "keep_classnames": false, + "keep_fargs": true, + "keep_fnames": false, + "keep_infinity": false, + "loops": true, + "negate_iife": true, + "properties": true, + "reduce_funcs": false, + "reduce_vars": false, + "side_effects": true, + "switches": true, + "typeofs": true, + "unsafe": false, + "unsafe_arrows": false, + "unsafe_comps": false, + "unsafe_Function": false, + "unsafe_math": false, + "unsafe_symbols": false, + "unsafe_methods": false, + "unsafe_proto": false, + "unsafe_regexp": false, + "unsafe_undefined": false, + "unused": true, + "const_to_let": true, + "pristine_globals": true +} diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/8737/input.js b/crates/swc_ecma_minifier/tests/fixture/issues/8737/input.js new file mode 100644 index 000000000000..c77842050387 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/8737/input.js @@ -0,0 +1,14 @@ +d(() => { + var obj = { + key: "some string", + }; + + var b = () => { + switch (a) { + default: + break; + } + return obj.key; + }; + return () => b; +}); \ No newline at end of file diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/8737/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/8737/output.js new file mode 100644 index 000000000000..2d9886ffdc7f --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/issues/8737/output.js @@ -0,0 +1,6 @@ +d(()=>{ + var obj = { + key: "some string" + }, b = ()=>(a, obj.key); + return ()=>b; +});