UglifyJS - Mangle函数但保留Function.prototype.name

时间:2017-10-05 11:12:10

标签: javascript typescript webpack ecmascript-6 uglifyjs

使用UglifyJS时,除非keep_fnames设置为true,否则功能名称会被修改。例如,以下的Typescript代码:

class Test {}
console.log(Test.name);

编译为JS为:

function Test() {}
console.log(Test.name);

将被解释为:

function t() {}
console.log(t.name);

并将t而不是test输出到控制台。

是否有办法(other than using keep_fnames option)在uglification后保留name属性? (我不想使用keep_fnames:true因为它会大大增加捆绑包的大小。

我想到的可能的解决方案:

  • 编写一个硬编码函数名称Test.name = 'Test'的Webpack插件,但这不会起作用,因为Function.prototype.name是一个只读属性;
  • 使用Typescript装饰器,元数据和反射API,但不为类发出design:type元数据,它只针对属性发出(我认为是因为Function.prototype.name存在,但我猜猜他们错过了这个边缘案例?)。

2 个答案:

答案 0 :(得分:2)

  

在uglification之后有没有办法(除了使用keep_fnames选项)保留name属性...

保持正确名称的唯一机制涉及该名称在输出文件中,因此简短答案为否。如果您想使用prototype.name,则需要保留该名称。

替代方案将涉及:

  1. 添加一个包含该名称的附加属性,该属性可能会引入错误并仍会占用文件中的空间
  2. 找到一个工具,将prototype.name的所有用途预先编译为字符串值...我不知道存在但你永远不知道!

答案 1 :(得分:2)

正如它解释hereFunction.prototype.name不能在客户端代码中依赖,因为函数原始名称的信息将在缩小过程中被销毁。防止它被重命名是快速而肮脏的修复。

name在某些浏览器中是只读且不可配置的,因此执行类似

的操作
class Test {
  static get name() {
    return 'Test';
  }
}

function Test() {}
Object.defineProperty(Test, 'name', { configurable: true, value: 'Test' });

会在大多数浏览器中修复它,但会在其他浏览器中导致模糊的兼容性问题(例如,Android 4.x浏览器)。

执行此操作的正确方法是从不依赖name在客户端代码中进行调试。至于Node.js和Electron,它取决于代码是否需要进行模糊处理。

如果某个类或函数应存在字符串标识符,则可以选择另一个静态属性名称,例如id或不受支持的传统displayName