使用 Uglify 的 keep_fnames 在生产模式下使用 Webpack 后重复 class 名称

Duplicate class names after using Webpack in production mode with Uglify's keep_fnames

我正在开发一个非常依赖 Function.prototype.name 的库(在父实例上设置快捷方式)。

class FooSection {}
class BarSection {}

class Page {
  constructor(sections) {
    for (let SectionClass of sections) {
      this[SectionClass.name] = new SectionClass(this);
    }
  }
}

let page = new Page([
  FooSection,
  BarSection
]);

这一切都很好,花花公子,直到从 Webpack 的优化开始。默认情况下会破坏函数名称,导致 类 和它们的 name 属性 被缩短。通常有用,不在这里。所以我去将适当的配置传递给 Webpack:

// ...
optimization: {
  minimizer: [
    new UglifyJsPlugin( {
                          uglifyOptions: {
                            keep_fnames: true
                          }
                        } )
  ]
}

根据文档,这应该保留我的函数名称。令人惊讶的是,名字是 重复的 ,所以 Page 突然变成了 Page_Page注意:这个代码块是我写的,但这大致就是输出的样子):

class FooSection_FooSection{}
class BarSection_BarSection{}
class Page_Page{
  constructor(t) {
    for(let s of t){this[s.name]=new s(this)}
  }
}
let p=new Page_Page([FooSection_FooSection,BarSection_BarSection])

这不能单独使用 UglifyJS 重现,所以它必须在工具链的某个地方(webpack -> uglifyjs-webpack-plugin -> uglifyjs),但我不知道在哪里。有人经历过吗?

版本如下:

更新:
根据评论,使用 TerserPlugin uglifier 似乎会出现同样的问题。

这是一个很老的话题,但我只是把它放在这里作为参考,因为我偶然发现了同样的问题,终于找到了原因。

此行为是由于 webpack ModuleConcatenationPlugin 出于性能原因将所有模块移至全局范围引起的。这可能会导致名称冲突,因此,webpack 重命名 类 并在它们前面加上它们的 file/module 名称。

您可以通过在您的 webpack 配置中将 concatenateModules 设置为 false 来禁用此行为。

module.exports = {
  //...
  optimization: {
    concatenateModules: false
  }
};

由于这不是错误并且您正在编写一个库,因此依赖此行为可能不是一个好主意。