fix corner cases with `exports` (#4691)
authorAlex Lam S.L <alexlamsl@gmail.com>
Thu, 25 Feb 2021 18:22:49 +0000 (18:22 +0000)
committerGitHub <noreply@github.com>
Thu, 25 Feb 2021 18:22:49 +0000 (02:22 +0800)
lib/compress.js
test/compress/exports.js

index 08b0987..b2825ad 100644 (file)
@@ -1079,16 +1079,19 @@ merge(Compressor.prototype, {
             return true;
         });
         def(AST_LambdaDefinition, function(tw, descend, compressor) {
-            var id = this.name.definition().id;
-            if (tw.defun_visited[id]) return true;
-            if (tw.defun_ids[id] !== tw.safe_ids) return true;
-            tw.defun_visited[id] = true;
-            this.inlined = false;
+            var fn = this;
+            var def = fn.name.definition();
+            var parent = tw.parent();
+            if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) def.single_use = false;
+            if (tw.defun_visited[def.id]) return true;
+            if (tw.defun_ids[def.id] !== tw.safe_ids) return true;
+            tw.defun_visited[def.id] = true;
+            fn.inlined = false;
             push(tw);
-            reset_variables(tw, compressor, this);
+            reset_variables(tw, compressor, fn);
             descend();
             pop(tw);
-            walk_defuns(tw, this);
+            walk_defuns(tw, fn);
             return true;
         });
         def(AST_Switch, function(tw, descend, compressor) {
@@ -5673,11 +5676,14 @@ merge(Compressor.prototype, {
                 }
             }
             if (!(sym instanceof AST_SymbolRef)) return;
-            if (compressor.exposed(sym.definition())) return;
+            var def = sym.definition();
+            if (export_defaults[def.id]) return;
+            if (compressor.exposed(def)) return;
             if (!can_drop_symbol(sym, nested)) return;
             return sym;
         };
         var assign_in_use = Object.create(null);
+        var export_defaults = Object.create(null);
         var find_variable = function(name) {
             find_variable = compose(self, 0, noop);
             return find_variable(name);
@@ -5748,7 +5754,11 @@ merge(Compressor.prototype, {
                         in_use.push(def);
                     }
                     if (node.extends) node.extends.walk(tw);
-                    var is_export = tw.parent() instanceof AST_ExportDefault;
+                    var is_export = false;
+                    if (tw.parent() instanceof AST_ExportDefault) {
+                        is_export = true;
+                        export_defaults[def.id] = true;
+                    }
                     node.properties.forEach(function(prop) {
                         if (prop.key instanceof AST_Node) prop.key.walk(tw);
                         if (!prop.value) return;
@@ -5770,7 +5780,11 @@ merge(Compressor.prototype, {
                         in_use.push(def);
                     }
                     initializations.add(def.id, node);
-                    if (!(tw.parent() instanceof AST_ExportDefault)) return true;
+                    if (tw.parent() instanceof AST_ExportDefault) {
+                        export_defaults[def.id] = true;
+                    } else {
+                        return true;
+                    }
                 }
                 if (node instanceof AST_Definitions) {
                     node.definitions.forEach(function(defn) {
index e069050..425b024 100644 (file)
@@ -227,3 +227,77 @@ keep_return_values: {
         }
     }
 }
+
+in_use: {
+    options = {
+        pure_getters: "strict",
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        export function f() {}
+        f.prototype.p = 42;
+    }
+    expect: {
+        export function f() {}
+        f.prototype.p = 42;
+    }
+}
+
+in_use_default: {
+    options = {
+        pure_getters: "strict",
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        export default function f() {}
+        f.prototype.p = 42;
+    }
+    expect: {
+        export default function f() {}
+        f.prototype.p = 42;
+    }
+}
+
+single_use: {
+    options = {
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        export function f() {
+            console.log("PASS");
+        }
+        f();
+    }
+    expect: {
+        export function f() {
+            console.log("PASS");
+        }
+        f();
+    }
+}
+
+single_use_default: {
+    options = {
+        reduce_vars: true,
+        toplevel: true,
+        unused: true,
+    }
+    input: {
+        export default function f() {
+            console.log("PASS");
+        }
+        f();
+    }
+    expect: {
+        export default function f() {
+            console.log("PASS");
+        }
+        f();
+    }
+}