Webpack: Class Style Components having names clobbered in Production build

webpack
typescript

#1

I have typescript code in a vue-cli project that relies on class names at runtime. This is working fine in development mode (yarn serve), but default production mode clobbers the typescript class names in minification - all of the pertinent classes have been renamed to t.

I’ve been poking around the webpack docs, and I’ve come up with a partially satisfying solution:

// vue.config.js

module.exports = {
  configureWebpack: {
        optimization: {
            minimize: false
        }
    }
}

The code now works in production, but (of course) is not minimized at all. I’d like to do better.

From the docs:

… Information collected by optimization.usedExports is used by other optimizations or code generation i.e. exports are not generated for unused exports, export names are mangled to single char identifiers when all usages are compatible…

But

module.exports = {
  configureWebpack: {
    optimization: {
      usedExports: false
    }
  }
}

Isn’t preserving the class names for me during build. I’ve tried a bunch of combinations of the following:

module.exports = {
    configureWebpack: {
        devtool: 'source-map',
        optimization: {
            minimize: false // works on its own, but makes a bigger output file
            // namedChunks: true,                 // | 
            // chunkIds: 'named',                 // | 
            // namedModules: true,                // | 
            // moduleIds: "named",                // | 
            // usedExports: false                 //  \
            // minimizer: [                       //   \
            //     new TerserPlugin({             //    =-  These do not work.
            //         terserOptions: {           //    =-  Class names are not emitted
            //             mangle: false,         //   /
            //             keep_classnames: true, //  /
            //             keep_fnames: true      // |
            //         }                          // |
            //     })                             // |
            // ]                                  // |    
        }
    }

But nothing other than turning minification off altogether seems to be having any effect.

Any suggestions?


#2

Pretty sure with minification it’s an all or nothing deal. Why do you need your class names to be unmodified in production?


#3

The short answer is ‘poor life choices’. The slightly longer answer is that there is a mixing of code and data in the application, and that class names are being used with dynamic components.


#4
module.exports = {
  configureWebpack: config => {
  const TerserPlugin = require('webpack-terser-plugin')

  // get current options
  const options = config.optimization.minimizer[0].options
  // set your own terser options
  options.terserOptions.keepClassname = true
  // replace current plugin instance with a fresh one
  config.optimization.minimizer[0] = new TerserPlugin(options)
  }
}

When we upgrade to webpack-chain v5 in the nach Vue CLI major, this will be configurable more elegantly.