it-swarm.com.ru

Uglify-js не искажает имена переменных

Пытаюсь подготовить хорошую среду сборки для моей библиотеки 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)
15
jayarjo

Хорошо, похоже, что последняя версия 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
14
jayarjo

По умолчанию uglify не портит имена верхнего уровня, может быть, это то, что вы видели? 

Попробуйте: - mt или --mangle-toplevel - также изменить имена в области верхнего уровня (по умолчанию мы этого не делаем).

10
axkibe

Если вы используете Uglify2, вы можете использовать TopLevel.figure_out_scope(). http://lisperator.net/uglifyjs/scope

Если вы используете Uglify1, это немного сложнее. Вот некоторый код, который я собрал, изменив код из файла squeeze_more.js Uglify :

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));
  });
}

Этот выше работает только для глобальных вызовов функций, но он дает вам обратный вызов, который выполняется, когда обходчик находит вызов неизвестного (глобального) метода.

Например, с учетом следующего ввода:

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

Он найдет вызов bar(1), но notbar(2) или bar(3).

1
nickf

Переменные в глобальной области видимости доступны для любого другого скрипта, поэтому Uglify не изменит их без специального переключения, если вам действительно нужно, чтобы они были видны. Вы можете либо использовать -mt/toplevel switch/setting, либо, что еще лучше, прекратить загрязнять глобальную область видимости и четко указать, что вы не намерены отображать эти переменные снаружи, а вставляете свой код в анонимную самопризывающую функцию, которая будет служить частной сферой.

0
Oleg V. Volkov