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

Posted

技术标签:

【中文标题】UglifyJS - Mangle 函数但保留 Function.prototype.name【英文标题】:UglifyJS - Mangle functions but preserve 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 包编写的外部库中访问的。 ***.com/questions/46561116/…的可能重复 @user5365075 这个库需要.name 做什么? 这个库使用类名来创建一个服务注册中心,并将这些服务注入到其他服务和类中。提供服务 ID 并不能解决任何问题,因为 lib 还依赖 .name 来获取要注入的类型。 Mangling 替换了函数名,从而破坏了 typescript 元数据,它不存储字符串类型值,而是对类的引用(编译时成为函数)。 【参考方案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,您需要保留该名称。

替代方案将涉及:

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

【讨论】:

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

以上是关于UglifyJS - Mangle 函数但保留 Function.prototype.name的主要内容,如果未能解决你的问题,请参考以下文章

UglifyJS2 删除块或文件末尾的想要的注释

在库中搜索 mangle

UglifyJS-- 对你的js做了什么

Webpacker、babel、uglifyjs-webpack-plugin - 不转换箭头函数,但仅在 Vue 文件中

uglifyjs2全局混淆

webpack打包后不能调用,改用uglifyjs打包压缩