18

试图为我的 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 专家,有什么提示我做错了什么吗?

更新

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

;(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)
4

4 回答 4

19

好的,似乎最新版本的 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
于 2012-06-12T11:50:00.367 回答
10

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

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

于 2012-06-09T11:42:08.540 回答
1

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

如果您使用的是 Uglify1,它会稍微复杂一些。这是我通过修改Uglifysqueeze_more.js文件中的代码而整理的一些代码:

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)找到or bar(3)

于 2013-05-26T17:15:17.817 回答
0

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

于 2012-06-09T11:45:21.530 回答