使用uglifyjs对嵌套的类和变量进行管理

时间:2013-05-02 09:47:09

标签: javascript minify uglifyjs uglifyjs2

我使用uglifyjs来缩小连接的文件集,这种方法很好但不够好。构建的lib使用名称空间,因此类,函数和常量存储在根名称空间变量中:

(function() {
  var root = { api:{}, core:{}, names:{} };

  /* util.js file */
  root.names.SOME_LONG_NAMED_CONST='Angel';

  /* Person.js file */
  root.core.Person = function(name) { this.name = name };

  /* API.js with the functions we want to expose */
  root.api.perform = function(param_for_api) { /* do something */ }

  window.lib_name.perform = root.api.perform;

})();

缩小为不那么小的版本

(function(){var a={api:{},core:{},names:{}};a.names.SOME_LONG_NAMED_CONST="Angel",a.core.Person=function(a){this.name=a},a.api.perform=function(){},window.lib_name.perform=a.api.perform})();

我理解uglify可能认为root var是一个必须保持原样并且不能更改的数据结构。有没有办法让uglify破坏根命名空间中的嵌套名称?

4 个答案:

答案 0 :(得分:8)

当您最小化Javascript时,您只能更改变量的名称,api,核心和名称不是变量,而是对象的属性。如果最小化器改变了这些,您可能会得到意想不到的结果。如果在您的代码中你会打电话

root["api"].perform = function()...

甚至是

之类的东西
function doIt(section, method, argument) {
    root[section][method](argument);
}
doIt('api','perform', 101);

所有完全合法的JS,但是最小化者永远无法弄清楚发生了什么。

答案 1 :(得分:4)

除了@JanMisker的观点(完全有效)之外,重写属性是不安全的,因为它们可以暴露在缩小范围之外的代码中。

虽然自执行函数有一个范围,如果代码只是

(function() {
  var root = { api:{}, core:{}, names:{} };
  root.names.SOME_LONG_NAMED_CONST='Angel';
  alert(root.names.SOME_LONG_NAMED_CONST); // some code that does something
})();

确实,在函数外部,无法访问根对象,因此重写属性名称是安全的,以下代码会产生相同的结果:

(function() {
  var a = { b:{}, c:{}, d:{} };
  a.d.e='Angel';
  alert(a.d.e);
})();

但即使您在私有范围内,您也可以访问,更重要的是从外部范围分配变量!想象一下:

(function() {
  var root = { api:{}, core:{}, names:{} };
  root.api.perform = function(param_for_api) { /* do something */ }
  window.lib_name = root.api;
})();

您不仅要展示一个函数,还要展示一个具有函数的对象。从窗口可见的任何地方都可以看到该功能。

因此,例如,在javascript控制台中编写以下内容会产生不同的结果:

window.lib_name.perform(asdf);

通过缩小,你必须写:

window.lib_name.f(asdf);

或类似的东西。

请记住,在缩小范围之外总会有代码。

拥有绝对最小的JS并不是至关重要的,但如果IT因某种原因而至关重要(例如:外星人绑架了你的继女,让她回来的唯一方法是将这个缩小到100个左右以下),您可以手动将不需要的长属性名称替换为较短的属性名称,只要确保它不会暴露在任何地方,并且不能通过关联数组表示法(root['api'])进行访问。

答案 2 :(得分:1)

正如@ Jan-Misker在他的回答中解释的那样,属性名称错误不是一个好主意,因为它可能会破坏你的代码。

但是,您可以通过将属性名称定义为局部变量来解决此问题,并将所有.properties修改为[keys],以缩小文件大小:

(function() {
  var API = 'api';
  var CORE = 'core';
  var NAMES = 'names';
  var SLNC = 'SOME_LONG_NAMED_CONST';

  var root = {};
  root[API]={};
  root[CORE]={};
  root[NAMES]={};

  /* util.js file */
  root[NAMES][SLNC] ='Angel';

  /* Person.js file */
  root[CORE].Person = function(name) { this.name = name };

  /* API.js with the functions we want to expose */
  root[API].perform = function(param_for_api) { /* do something */ }

  window.lib_name.perform = root[API].perform;

})();

因为现在所有的属性都变成了一个局部变量,所以uglify js会破坏/缩短变量名,因此整体文件大小减少了:

!function(){var a="api",b="core",c="names",d="SOME_LONG_NAMED_CONST",e={};e[a]={},e[b]={},e[c]={},e[c][d]="Angel",e[b].Person=function(a){this.name=a},e[a].perform=function(){},window.lib_name.perform=e[a].perform}();

然而,缩小文件大小并不意味着您将在真实服务器上缩短下载时间,因为通常我们的http传输是gzip压缩,大多数重复将由您的http服务器压缩,并且它比人类做得更好。

答案 3 :(得分:1)

最新版本的uglify(今天)有对象属性重整,见v2.4.18。它还支持保留文件,用于排除对象属性和不希望损坏的变量。看看吧。

使用--mangle-props选项和--reserved-file filename1.json filename2.json等....