8

我使用 UglifyJS 来缩小一组连接的文件,效果很好,但还不够好。构建的库使用命名空间,因此类、函数和常量存储在根命名空间变量中:

(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 是一种数据结构,必须保持原样并且不能更改。有没有办法让 UglifyJS 破坏根命名空间中的嵌套名称?

4

5 回答 5

8

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

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

甚至像

function doIt(section, method, argument) {
    root[section][method](argument);
}
doIt('api','perform', 101);

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

于 2013-05-02T09:53:16.133 回答
7

我一直在尝试使用--mangle-propsUglifyJS2 并且可以告诉你:'它弄得一团糟'。

正如有人指出的那样:'开发人员应该决定要破坏哪些属性,而不是 uglifyjs '

我正在使用以下选项解决问题:

--mangle-props
--mangle-regexp="/_$/"

正则表达式匹配末尾带有下划线的任何属性。

您要求在根命名空间中破坏嵌套名称。所以,你的代码:

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

  root.names.SOME_LONG_NAMED_CONST_='Angel';

  root.core.Person_ = function(name) { this.name = name };

  root.api.perform_ = function(param_for_api) {  }

  window.lib_name.perform = root.api.perform;
})();

会导致:

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

命令: uglifyjs --beautify --mangle --mangle-props --mangle-regex="/_$/" -- file.js

如果你想破坏第一级的根命名空间(api, core, names),只需在它们上加一个下划线(api_, core_, names_),你就可以控制;)

附带说明:当您修改其他 js 文件可用的属性时,您应该使用相同的命令将所有文件组合在一起,因此所有文件都将使用相同的标识符。

于 2015-08-15T03:47:29.307 回答
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 并不是那么重要,但如果出于某种原因这很重要(例如:外星人绑架了你的继女,让她回来的唯一方法是将其缩小到 100 个左右字符以下),你可以手动将不希望的长属性名称替换为较短的属性名称,只需确保它不会在任何地方公开,并且不会通过关联数组表示法 ( root['api']) 访问。

于 2013-05-02T11:21:10.420 回答
1

The latest release of uglify (today) has object property mangling, see v2.4.18. It also supports reserved files for excluding both object properties and variables that you don't want mangled. Check it out.

Use the --mangle-props option and --reserved-file filename1.json filename2.json etc....

于 2015-03-29T13:07:34.320 回答
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 服务器压缩,它比人类做得更好。

于 2014-03-12T21:47:03.090 回答