【问题标题】:Uglify-js doesn't mangle variable namesUglify-js 不会破坏变量名
【发布时间】:2012-06-09 07:13:05
【问题描述】:

尝试为我的 js 库准备良好的构建环境。根据网络上的评论,UglifyJS 似乎是最好的压缩模块之一,在 NodeJS 下工作。所以这里是压缩代码的最佳推荐方法:

var jsp = require("uglify-js").parser;
var pro = require("uglify-js").uglify;

var orig_code = "... JS code here";
var ast = jsp.parse(orig_code); // parse code and get the initial AST
ast = pro.ast_mangle(ast); // get a new AST with mangled names
ast = pro.ast_squeeze(ast); // get an AST with compression optimizations
var final_code = pro.gen_code(ast); // compressed code here

如此处所见,pro.ast_mangle(ast) 应该修改变量名,但事实并非如此。我从这个管道中得到的只是 javascript 代码,没有空格。起初我认为我的代码没有针对压缩进行优化,但后来我用Google Closure 进行了尝试,得到了相当大的压缩(变量名和所有内容都被破坏了)。

UglifyJS 专家,有什么提示我做错了吗?

更新

实际代码太大,无法在此处引用,但即使是这样的 sn-p 也不会被破坏:

;(function(window, document, undefined) {

    function o(id) {
        if (typeof id !== 'string') {
            return id;  
        }
        return document.getElementById(id);
    }   

    // ...

    /** @namespace */
    window.mOxie = o;

}(window, document));

这就是我得到的(我猜只有空格被剥离):

(function(window,document,undefined){function o(id){return typeof id!="string"?id:document.getElementById(id)}window.mOxie=window.o=o})(window,document)

【问题讨论】:

  • 我认为如果您发布一小段代码以及您发现问题的结果会有所帮助。
  • 我想也许我缺少一些选项。现在用小 sn-p 更新。显然它与我的环境有关?.. 虽然不确定从哪里开始调试它或者什么可能会影响 uglify-js 在请求时破坏的能力。
  • 嗯,通过 UglifyJS 的网站,我得到了:(function(a,b,c){function d(a){return typeof a!="string"?a:b.getElementById(a)}a.mOxie=a.o=d})(window,document) 你确定你打开了正确的开关吗?
  • 如果我的问题中的 uglifyJS 调用代码打开了正确的开关,那么 - 是的:|
  • 奇怪...我在网站上尝试过,也得到了很好的压缩代码。所以这是我这边的事情......但不知道是什么。我正在使用我的问题中的代码来调用它。

标签: javascript performance compression minify uglifyjs


【解决方案1】:

好的,最新版本的 Uglify JS 似乎需要将 mangle 选项显式传递为 true,否则它不会损坏任何东西。像这样:

var jsp = require("uglify-js").parser;
var pro = require("uglify-js").uglify;

var orig_code = "... JS code here";
var options = {
    mangle: true
};

var ast = jsp.parse(orig_code); // parse code and get the initial AST
ast = pro.ast_mangle(ast, options); // get a new AST with mangled names
ast = pro.ast_squeeze(ast); // get an AST with compression optimizations
var final_code = pro.gen_code(ast); // compressed code here

【讨论】:

    【解决方案2】:

    默认情况下 uglify 不会破坏顶级名称,也许这就是你所看到的?

    尝试: -mt 或 --mangle-toplevel — 也在顶层范围内修改名称(默认情况下我们不这样做)。

    【讨论】:

    • 分别为ast = uglify.uglify.ast_mangle(ast, {toplevel: true});
    • 我所有的代码都被封装成匿名自调用函数。我用 sn-p 更新了我的问题。并提示我如何调试这种情况?
    • 顶级对我不起作用。仍然没有修改变量。一切都在匿名函数中。全局范围内没有任何可用的内容。
    【解决方案3】:

    如果您使用的是 Uglify2,则可以使用 TopLevel.figure_out_scope()http://lisperator.net/uglifyjs/scope

    如果您使用的是 Uglify1,它会稍微复杂一些。这是我通过修改Uglify's squeeze_more.js file中的代码拼凑起来的一些代码:

    function eachGlobalFunctionCall(ast, callback) {
      var w = uglify.uglify.ast_walker(),
          walk = w.walk,
          MAP = uglify.uglify.MAP,
          scope;
    
      function with_scope(s, cont) {
        var save = scope, ret;
        scope = s;
        ret = cont();
        scope = save;
        return ret;
      }
    
      function _lambda(name, args, body) {
        return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ];
      }
    
      w.with_walkers({
        "function": _lambda,
        "defun": _lambda,
        "toplevel": function(body) {
          return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ];
        },
        "call": function(expr, args) {
          var fnName = expr[1];
    
          if (!scope.has(fnName)) {    // <--- here's the important part
            callback(fnName, args, scope);
          }
        }
      }, function() {
        return walk(uglify.uglify.ast_add_scope(ast));
      });
    }
    

    上面的这个仅适用于全局函数调用,但它会为您提供一个回调,该回调会在 walker 找到对未知(全局)方法的调用时执行。

    例如,给定以下输入:

    function foo () {
      bar(1);
      (function () {
        function bar() { }
        bar(2);
        (function () {
          bar(3);
        }());
      }());
    }
    

    它会找到电话 bar(1)不会 bar(2)bar(3)

    【讨论】:

      【解决方案4】:

      全局范围内的变量可用于任何其他脚本,因此 Uglify 不会在没有特殊开关的情况下更改它们,以防您真的需要它们可见。您可以使用-mt/toplevel 开关/设置,或者,更好的是,停止污染全局范围并明确表明您不打算让这些变量在外部看到,而是将您的代码框架化为匿名自调用将用作私有作用域的函数。

      【讨论】:

      • “将您的代码框架化为匿名自调用函数”这就是我实际所做的。只暴露了一个顶级对象。
      • 示例中的每个变量都是外部全局范围的变量。
      • 是的,来自外部作用域的变量作为参数传递给自调用匿名函数。这不是使它们可用于修饰(在函数内部)吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-24
      • 2016-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多