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

use*_*075 6 javascript uglifyjs typescript ecmascript-6 webpack

使用 UglifyJS 时,函数名称会被修改,除非keep_fnames设置为true. 例如,以下打字稿代码:

class Test {}
console.log(Test.name);
Run Code Online (Sandbox Code Playgroud)

编译成JS:

function Test() {}
console.log(Test.name);
Run Code Online (Sandbox Code Playgroud)

将被丑化为:

function t() {}
console.log(t.name);
Run Code Online (Sandbox Code Playgroud)

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

有没有办法(除了使用keep_fnames选项)name在丑化后保留财产?(我不想使用,keep_fnames:true因为它会大大增加捆绑包的大小。

我想到的可能解决方案:

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

Est*_*ask 3

正如这里所解释的,Function.prototype.name不能在客户端代码中依赖,因为函数原始名称的信息将在缩小过程中被破坏。防止它被重命名是一种快速而肮脏的修复方法。

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

class Test {
  static get name() {
    return 'Test';
  }
}
Run Code Online (Sandbox Code Playgroud)

或者

function Test() {}
Object.defineProperty(Test, 'name', { configurable: true, value: 'Test' });
Run Code Online (Sandbox Code Playgroud)

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

执行此操作的正确方法是除了调试之外永远不要依赖name客户端代码进行任何操作。至于Node.js和Electron,就看代码是否需要混淆了。

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