Javascript Uglify-js 不会破坏变量名

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10959154/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 03:47:01  来源:igfitidea点击:

Uglify-js doesn't mangle variable names

javascriptperformancecompressionminifyuglifyjs

提问by jayarjo

Trying to prepare good build environment for my js library. According to reviews on the web UglifyJSseems to be one of the best compressing modules out there, working under NodeJS. So here is best recommended way of minifying the code:

尝试为我的 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

As seen here, pro.ast_mangle(ast)should mangle variable names, but it doesn't. All I get out of this pipe is javascript code, with no spaces. At first I thought that my code was not optimized for compression, but then I tried it with Google Closureand got quite a compression (with mangled variable names and everything).

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

UglifyJS experts, any hint to what I'm doing wrong?

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

UPDATE:

更新

Actual code is too large to reference here, but even a snippet like this doesn't get mangled:

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

;(function(window, document, undefined) {

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

    // ...

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

}(window, document));

This is what I get (only spaces get stripped I guess):

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

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

采纳答案by jayarjo

Ok, it seems that the latest version of Uglify JS requires mangle option to be explicitly passed as true, otherwise it won't mangle anything. Like this:

好吧,似乎最新版本的 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

回答by axkibe

By default uglify won't mangle toplevel names, maybe thats what you seen?

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

Try: -mt or --mangle-toplevel — mangle names in the toplevel scope too (by default we don't do this).

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

回答by nickf

If you're using Uglify2, you can use TopLevel.figure_out_scope(). http://lisperator.net/uglifyjs/scope

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

If you're using Uglify1, it's a little more complicated. Here's some code I put together by modifying the code from Uglify's squeeze_more.jsfile:

如果您使用的是 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));
  });
}

This one above only works on global function calls, but it gives you a callback which is executed as the walker finds a call to an unknown (global) method.

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

For example, given the following input:

例如,给定以下输入:

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

It would find the call bar(1)but notbar(2)or bar(3).

它会找到调用,bar(1)不会找到bar(2)or bar(3)

回答by Oleg V. Volkov

Variables in global scope are available to any other script, so Uglify won't change them without special switch, in case you really need them to be visible. You can either use -mt/toplevelswitch/setting, or, better, yet, stop polluting global scope and clearly indicate that you don't intend for those variables to be seen outside, but framing your code into anonymous self-invoking function that will serve as private scope.

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