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, любой намек на то, что я делаю неправильно?
UPDATE
Фактический код слишком велик, чтобы ссылаться на него, но даже такой фрагмент не выглядит искаженным:
;(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)
Ответы
Ответ 1
Хорошо, похоже, что последняя версия Uglify JS требует, чтобы параметр mangle явно передавался как истинный, иначе он ничего не будет калечить. Вот так:
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 не будет искажать имена верхнего уровня, может быть, это то, что вы видели?
Try:
-mt или --mangle-toplevel - также манит имена в области верхнего уровня (по умолчанию мы этого не делаем).
Ответ 3
Если вы используете Uglify2, вы можете использовать TopLevel.figure_out_scope()
. http://lisperator.net/uglifyjs/scope
Если вы используете Uglify1, это немного сложнее. Вот код, который я собрал, изменив код из Uglify 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 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)
, но не bar(2)
или bar(3)
.
Ответ 4
Переменные в глобальной области доступны для любого другого script, поэтому Uglify не будет изменять их без специального переключателя, если вам действительно нужно, чтобы они были видимыми. Вы можете либо использовать параметр -mt
/toplevel
switch/setting, либо, тем не менее, прекратить загрязнение глобальной области и четко указать, что вы не собираетесь, чтобы эти переменные были видны снаружи, но обрамление вашего кода в анонимный self- вызывающей функции, которая будет служить частной областью.