webpackuglifyjs

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


I'm working on a library that relies on Function.prototype.name a lot (to set shortcuts on the parent instance).

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
]);

This works all fine and dandy, until mangling from Webpack's optimization kicks in. That mangles function names by default, resulting in classes and their name property being shortened. Useful usually, not here. So I went and passed the appropriate configuration to Webpack:

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

According to the documentation, this should preserve my function names. Astonishingly, what happens is that the names are duplicated instead, so Page becomes Page_Page suddenly (note: this code block is written by me, but that's roughly what the output looks like):

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])

This is not reproducible using UglifyJS alone, so it must be somewhere inside the toolchain (webpack -> uglifyjs-webpack-plugin -> uglifyjs), but I can't figure out where. Has anyone experienced this yet?

Versions as follows:

Update:
As per the comments, the same issue seems to occur using the TerserPlugin uglifier.


Solution

  • It's a pretty old topic, but I just put it here for reference as I stumbled upon the same issue and finally found out the reason.

    This behavior is caused by webpack's ModuleConcatenationPlugin that moves all modules into a global scope for performance reasons. That might cause name conflicts and thus, webpack renames the classes and prefixes them with their file/module names.

    You can disable this behavior by setting concatenateModules to false in your webpack config.

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

    Since this is not a bug and you're writing a library, it's probably not a good idea to rely on this behavior though.