【问题标题】:UglifyJS - Mangle functions but preserve Function.prototype.nameUglifyJS - Mangle 函数但保留 Function.prototype.name
【发布时间】:2018-03-16 23:45:40
【问题描述】:

使用 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)在丑化后保留name 属性? (我不想使用keep_fnames:true,因为它会大大增加捆绑包的大小。

我想到的可能解决方案:

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

【问题讨论】:

  • 你能写一个 Webpack 插件,用"Test" 替换Test.name 的实例吗?类似于 DefinePlugin 所做的。
  • 我猜是的,但在这种情况下,我简化了示例。在我的实际用例中,.name 属性是从我作为私有 npm 包编写的外部库中访问的。
  • @user5365075 这个库需要.name 做什么?
  • 这个库使用类名来创建一个服务注册中心,并将这些服务注入到其他服务和类中。提供服务 ID 并不能解决任何问题,因为 lib 还依赖 .name 来获取要注入的类型。 Mangling 替换了函数名,从而破坏了 typescript 元数据,它不存储字符串类型值,而是对类的引用(编译时成为函数)。

标签: javascript typescript webpack ecmascript-6 uglifyjs


【解决方案1】:

正如here 所解释的,Function.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

【讨论】:

  • 老实说,答案很好。我喜欢使用displayName 的想法。太糟糕了,这是一个不可避免的解决方法。
  • 不客气。不可避免,是的。请注意name 的情况与design:type 的道具不同。道具具有固定的名称(它们也可以被缩小器破坏,但这几乎是不可取的)。函数没有。
【解决方案2】:

有没有办法(除了使用keep_fnames选项)在丑化后保留名称属性...

保持正确名称的唯一机制是该名称存在于输出文件中,因此简短的回答是否定的。如果您想使用prototype.name,您需要保留该名称。

替代方案将涉及:

  1. 添加包含名称的附加属性,这可能会导致错误并且仍会占用文件空间
  2. 正在寻找一种工具,可以使用字符串值预编译 prototype.name 的所有用法...我不知道有一个工具存在,但你永远不知道!

【讨论】:

  • 选项 2 我非常喜欢 :) 我想写这样一个 webpack 插件是可行的,但我担心这在这种情况下不起作用,因为我使用函数名的代码包含在一个外部库。因此,.name 可以在外部库中访问。
  • 解决某些用途将非常困难,当然,如果在多种情况下用途不同(可能是这种情况,否则您不会查看价值) .
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多