私のjsライブラリ用の良いビルド環境を準備しようとしています。ウェブ上のレビューによると glifyJS は、NodeJSの下で動作する、最も優れた圧縮モジュールの1つであるようです。だからここにコードを縮小する最良の方法があります:
_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)
_
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
デフォルトでは、uglifyはトップレベルの名前を壊しません。
試してください:-mtまたは--mangle-toplevel —トップレベルスコープ内の名前もマングルします(デフォルトではこれを行いません)。
Uglify2を使用している場合は、TopLevel.figure_out_scope()
を使用できます。 http://lisperator.net/uglifyjs/scope
Uglify1を使用している場合は、少し複雑になります。これが glifyの_squeeze_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));
});
}
_
上記の1つはグローバル関数呼び出しでのみ機能しますが、ウォーカーが未知の(グローバル)メソッドへの呼び出しを見つけると実行されるコールバックを提供します。
たとえば、次の入力があるとします。
_function foo () {
bar(1);
(function () {
function bar() { }
bar(2);
(function () {
bar(3);
}());
}());
}
_
これはbar(1)
という呼び出しを検出しますが、notbar(2)
またはbar(3)
を検出します。
グローバルスコープの変数は他のスクリプトで使用できるので、本当に表示する必要がある場合に備えて、特別なスイッチなしでUglifyが変数を変更することはありません。 -mt
/toplevel
スイッチ/設定、または、さらに良いことに、グローバルスコープの汚染を停止し、これらの変数が外部に見られることを意図せず、コードを匿名の自己呼び出し関数にフレーム化することを明確に示すプライベートスコープとして機能します。