[Pkg-javascript-commits] [uglifyjs] 168/491: improve usability of name cache under `minify()` (#2176)

Jonas Smedegaard dr at jones.dk
Wed Feb 14 19:51:32 UTC 2018


This is an automated email from the git hooks/post-receive script.

js pushed a commit to annotated tag debian/3.3.10-1
in repository uglifyjs.

commit bdeadffbf582b393dbc14a45b3e69ddf16f47690
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date:   Thu Jun 29 12:48:34 2017 +0800

    improve usability of name cache under `minify()` (#2176)
    
    fixes #2174
---
 README.md            | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--
 bin/uglifyjs         | 27 ++------------------------
 lib/minify.js        | 36 ++++++++++++++++++++++++++++++++++-
 test/mocha/minify.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 140 insertions(+), 28 deletions(-)

diff --git a/README.md b/README.md
index de2c2c9..c277f65 100644
--- a/README.md
+++ b/README.md
@@ -111,7 +111,7 @@ a double dash to prevent input files being used as option arguments:
                                 By default UglifyJS will not try to be IE-proof.
     --keep-fnames               Do not mangle/drop function names.  Useful for
                                 code relying on Function.prototype.name.
-    --name-cache                File to hold mangled name mappings.
+    --name-cache <file>         File to hold mangled name mappings.
     --self                      Build UglifyJS as a library (implies --wrap UglifyJS)
     --source-map [options]      Enable source map/specify source map options:
                                 `base`  Path to compute relative paths from input files.
@@ -383,7 +383,47 @@ var code = {
 var options = { toplevel: true };
 var result = UglifyJS.minify(code, options);
 console.log(result.code);
-// console.log(function(n,o){return n+o}(3,7));
+// console.log(3+7);
+```
+
+The `nameCache` option:
+```javascript
+var options = {
+    mangle: {
+        toplevel: true,
+    },
+    nameCache: {}
+};
+var result1 = UglifyJS.minify({
+    "file1.js": "function add(first, second) { return first + second; }"
+}, options);
+var result2 = UglifyJS.minify({
+    "file2.js": "console.log(add(1 + 2, 3 + 4));"
+}, options);
+console.log(result1.code);
+// function n(n,r){return n+r}
+console.log(result2.code);
+// console.log(n(3,7));
+```
+
+You may persist the name cache to the file system in the following way:
+```javascript
+var cacheFileName = "/tmp/cache.json";
+var options = {
+    mangle: {
+        properties: true,
+    },
+    nameCache: JSON.parse(fs.readFileSync(cacheFileName, "utf8"))
+};
+fs.writeFileSync("part1.js", UglifyJS.minify({
+    "file1.js": fs.readFileSync("file1.js", "utf8"),
+    "file2.js": fs.readFileSync("file2.js", "utf8")
+}, options).code, "utf8");
+fs.writeFileSync("part2.js", UglifyJS.minify({
+    "file3.js": fs.readFileSync("file3.js", "utf8"),
+    "file4.js": fs.readFileSync("file4.js", "utf8")
+}, options).code, "utf8");
+fs.writeFileSync(cacheFileName, JSON.stringify(options.nameCache), "utf8");
 ```
 
 An example of a combination of `minify()` options:
@@ -461,6 +501,13 @@ if (result.error) throw result.error;
 - `toplevel` (default `false`) - set to `true` if you wish to enable top level
   variable and function name mangling and to drop unused variables and functions.
 
+- `nameCache` (default `null`) - pass an empty object `{}` or a previously
+  used `nameCache` object if you wish to cache mangled variable and
+  property names across multiple invocations of `minify()`. Note: this is
+  a read/write property. `minify()` will read the name cache state of this
+  object and update it during minification so that it may be
+  reused or externally persisted by the user.
+
 - `ie8` (default `false`) - set to `true` to support IE8.
 
 ## Minify options structure
@@ -487,6 +534,7 @@ if (result.error) throw result.error;
     sourceMap: {
         // source map options
     },
+    nameCache: null, // or specify a name cache object
     toplevel: false,
     ie8: false,
 }
diff --git a/bin/uglifyjs b/bin/uglifyjs
index f4feb39..68d67c2 100755
--- a/bin/uglifyjs
+++ b/bin/uglifyjs
@@ -106,17 +106,8 @@ if (program.mangleProps) {
     if (typeof options.mangle != "object") options.mangle = {};
     options.mangle.properties = program.mangleProps;
 }
-var cache;
 if (program.nameCache) {
-    cache = JSON.parse(read_file(program.nameCache, "{}"));
-    if (options.mangle) {
-        if (typeof options.mangle != "object") options.mangle = {};
-        options.mangle.cache = to_cache("vars");
-        if (options.mangle.properties) {
-            if (typeof options.mangle.properties != "object") options.mangle.properties = {};
-            options.mangle.properties.cache = to_cache("props");
-        }
-    }
+    options.nameCache = JSON.parse(read_file(program.nameCache, "{}"));
 }
 if (program.output == "ast") {
     options.output = {
@@ -266,9 +257,7 @@ function run() {
         print(result.code);
     }
     if (program.nameCache) {
-        fs.writeFileSync(program.nameCache, JSON.stringify(cache, function(key, value) {
-            return value instanceof UglifyJS.Dictionary ? value.toObject() : value;
-        }));
+        fs.writeFileSync(program.nameCache, JSON.stringify(options.nameCache));
     }
     if (result.timings) for (var phase in result.timings) {
         print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
@@ -381,18 +370,6 @@ function parse_source_map() {
     }
 }
 
-function to_cache(key) {
-    if (cache[key]) {
-        cache[key].props = UglifyJS.Dictionary.fromObject(cache[key].props);
-    } else {
-        cache[key] = {
-            cname: -1,
-            props: new UglifyJS.Dictionary()
-        };
-    }
-    return cache[key];
-}
-
 function skip_key(key) {
     return skip_keys.indexOf(key) >= 0;
 }
diff --git a/lib/minify.js b/lib/minify.js
index cc638be..b4bfe45 100644
--- a/lib/minify.js
+++ b/lib/minify.js
@@ -27,6 +27,23 @@ function set_shorthand(name, options, keys) {
     }
 }
 
+function init_cache(cache) {
+    if (!cache) return;
+    if (!("cname" in cache)) cache.cname = -1;
+    if (!("props" in cache)) {
+        cache.props = new Dictionary();
+    } else if (!(cache.props instanceof Dictionary)) {
+        cache.props = Dictionary.fromObject(cache.props);
+    }
+}
+
+function to_json(cache) {
+    return {
+        cname: cache.cname,
+        props: cache.props.toObject()
+    };
+}
+
 function minify(files, options) {
     var warn_function = AST_Node.warn_function;
     try {
@@ -35,6 +52,7 @@ function minify(files, options) {
             ie8: false,
             keep_fnames: false,
             mangle: {},
+            nameCache: null,
             output: {},
             parse: {},
             sourceMap: false,
@@ -52,7 +70,7 @@ function minify(files, options) {
         set_shorthand("warnings", options, [ "compress" ]);
         if (options.mangle) {
             options.mangle = defaults(options.mangle, {
-                cache: null,
+                cache: options.nameCache && (options.nameCache.vars || {}),
                 eval: false,
                 ie8: false,
                 keep_fnames: false,
@@ -60,6 +78,16 @@ function minify(files, options) {
                 reserved: [],
                 toplevel: false,
             }, true);
+            if (options.nameCache && options.mangle.properties) {
+                if (typeof options.mangle.properties != "object") {
+                    options.mangle.properties = {};
+                }
+                if (!("cache" in options.mangle.properties)) {
+                    options.mangle.properties.cache = options.nameCache.props || {};
+                }
+            }
+            init_cache(options.mangle.cache);
+            init_cache(options.mangle.properties.cache);
         }
         if (options.sourceMap) {
             options.sourceMap = defaults(options.sourceMap, {
@@ -153,6 +181,12 @@ function minify(files, options) {
                 }
             }
         }
+        if (options.nameCache && options.mangle) {
+            if (options.mangle.cache) options.nameCache.vars = to_json(options.mangle.cache);
+            if (options.mangle.properties && options.mangle.properties.cache) {
+                options.nameCache.props = to_json(options.mangle.properties.cache);
+            }
+        }
         if (timings) {
             timings.end = Date.now();
             result.timings = {
diff --git a/test/mocha/minify.js b/test/mocha/minify.js
index b4722ce..88e9c4e 100644
--- a/test/mocha/minify.js
+++ b/test/mocha/minify.js
@@ -1,6 +1,7 @@
 var Uglify = require('../../');
 var assert = require("assert");
 var readFileSync = require("fs").readFileSync;
+var run_code = require("../sandbox").run_code;
 
 function read(path) {
     return readFileSync(path, "utf8");
@@ -20,6 +21,58 @@ describe("minify", function() {
         assert.strictEqual(result.code, "alert(2);");
     });
 
+    it("Should work with mangle.cache", function() {
+        var cache = {};
+        var original = "";
+        var compressed = "";
+        [
+            "bar.es5",
+            "baz.es5",
+            "foo.es5",
+            "qux.js",
+        ].forEach(function(file) {
+            var code = read("test/input/issue-1242/" + file);
+            var result = Uglify.minify(code, {
+                mangle: {
+                    cache: cache,
+                    toplevel: true
+                }
+            });
+            if (result.error) throw result.error;
+            original += code;
+            compressed += result.code;
+        });
+        assert.strictEqual(JSON.stringify(cache).slice(0, 20), '{"cname":5,"props":{');
+        assert.strictEqual(compressed, 'function n(n){return 3*n}function r(n){return n/2}function c(o){l("Foo:",2*o)}var l=console.log.bind(console);var f=n(3),i=r(12);l("qux",f,i),c(11);');
+        assert.strictEqual(run_code(compressed), run_code(original));
+    });
+
+    it("Should work with nameCache", function() {
+        var cache = {};
+        var original = "";
+        var compressed = "";
+        [
+            "bar.es5",
+            "baz.es5",
+            "foo.es5",
+            "qux.js",
+        ].forEach(function(file) {
+            var code = read("test/input/issue-1242/" + file);
+            var result = Uglify.minify(code, {
+                mangle: {
+                    toplevel: true
+                },
+                nameCache: cache
+            });
+            if (result.error) throw result.error;
+            original += code;
+            compressed += result.code;
+        });
+        assert.strictEqual(JSON.stringify(cache).slice(0, 28), '{"vars":{"cname":5,"props":{');
+        assert.strictEqual(compressed, 'function n(n){return 3*n}function r(n){return n/2}function c(o){l("Foo:",2*o)}var l=console.log.bind(console);var f=n(3),i=r(12);l("qux",f,i),c(11);');
+        assert.strictEqual(run_code(compressed), run_code(original));
+    });
+
     describe("keep_quoted_props", function() {
         it("Should preserve quotes in object literals", function() {
             var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/uglifyjs.git



More information about the Pkg-javascript-commits mailing list