web-dev-qa-db-fra.com

Uglify-js ne modifie pas les noms de variables

Essayer de préparer un bon environnement de compilation pour ma bibliothèque js. Selon des critiques sur le Web UglifyJS semble être l’un des meilleurs modules de compression du marché, fonctionnant sous NodeJS. Voici donc le meilleur moyen recommandé de minifier le code:

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

Comme on le voit ici, pro.ast_mangle(ast) devrait modifier les noms de variables, mais ce n’est pas le cas. Tout ce que je tire de ce tuyau, c'est du code javascript, sans espaces. Au début, je pensais que mon code n'était pas optimisé pour la compression, mais je l'ai ensuite essayé avec Google Closure et j'ai obtenu une compression assez importante (avec des noms de variables mutilés et tout le reste). 

Experts UglifyJS, avez-vous une idée de ce que je fais mal?

UPDATE:

Le code réel est trop volumineux pour être référencé ici, mais même un extrait de code comme celui-ci ne sera pas mutilé:

;(function(window, document, undefined) {

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

    // ...

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

}(window, document));

C'est ce que je reçois (seuls les espaces sont dépouillés, je suppose):

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

Ok, il semble que la dernière version de Uglify JS exige que l’option mangle soit explicitement passée à true, sinon elle ne modifiera rien. Comme ça:

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

Par défaut, Uglify ne supprimera pas les noms de niveau supérieur, c’est peut-être ce que vous avez vu? 

Essayez: - mt ou --mangle-toplevel - modifiez également les noms dans la portée de niveau supérieur (par défaut, nous ne le faisons pas).

10
axkibe

Si vous utilisez Uglify2, vous pouvez utiliser TopLevel.figure_out_scope(). http://lisperator.net/uglifyjs/scope

Si vous utilisez Uglify1, c'est un peu plus compliqué. Voici un code que j'ai rassemblé en modifiant le code à partir de Le fichier squeeze_more.js de 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));
  });
}

Celui ci-dessus ne fonctionne que sur les appels de fonctions globales, mais il vous donne un rappel qui est exécuté lorsque le marcheur trouve un appel à une méthode inconnue (globale).

Par exemple, étant donné l'entrée suivante:

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

Il trouverait l'appel bar(1) mais not bar(2) ou bar(3).

1
nickf

Les variables de portée globale sont disponibles pour tout autre script. Uglify ne les modifiera donc pas sans commutateur spécial, au cas où vous auriez vraiment besoin qu'elles soient visibles. Vous pouvez utiliser le paramètre/paramètre -mt/toplevel ou, mieux encore, arrêter la portée globale polluante et indiquer clairement que vous ne souhaitez pas que ces variables soient vues à l'extérieur, mais cadrer votre code dans une fonction invocatrice anonyme qui servir de périmètre privé.

0
Oleg V. Volkov