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的主要内容,如果未能解决你的问题,请参考以下文章
Webpacker、babel、uglifyjs-webpack-plugin - 不转换箭头函数,但仅在 Vue 文件中