Webpack including unused exports in final bundle (not tree shaking)

Paul T. picture Paul T. · Feb 3, 2018 · Viewed 8.1k times · Source

I have a setup where a library's index.js (main entry point) exports everything in the lib... so its setup like this:

export * from "./mod1"
export * from "./mod2"
// etc...

(take a look)

When I import 1 of the exported libraries from that entry point, looks like Webpack is not able to tree-shake the output. running webpack -p is actually including the entire library in the bundle, although only one export was imported. Runing webpack (non-production bundle) does show unused harmony export .... throughout the file (167 times), but why are they not being dropped?

I have a test setup showing this problem here: https://github.com/purtuga/webpack-bundle-test

Hoping someone (smarter than me :) ) can help identify what I am doing wrong.

/Paul

Answer

Priyesh Diukar picture Priyesh Diukar · Feb 16, 2018

When you bundle the application without transformations (like Babel) and minification (like UglifyJS), you get: unused harmony export.

Now Webpack 2+ only marks code unused and doesn’t export it inside the module. It pulls everything and leaves unused code for minification libraries.

You can use UglifyJS with babel for this. UglifyJS doesn’t support the new language features of Javascript ES2015+ yet. You will need Babel to transpile the code to ES5 and then use UglifyJS to clean up the unused code.

You will need .babelrc file with:

We have to tell the preset (in our case babel-preset-env) to skip the module transpilation.

{
  "presets": [
    ["env", {
      "loose": true,
      "modules": false
    }]
  ]
}

and corresponding webpack config:

module: {
  rules: [
    { test: /\.js$/, loader: 'babel-loader' }
  ]
},

plugins: [
  new webpack.LoaderOptionsPlugin({
    minimize: true,
    debug: false
  }),
  new webpack.optimize.UglifyJsPlugin({
    compress: {
      warnings: true
    },
    output: {
      comments: false
    },
    sourceMap: false
  })
]

OR

Babili is a better option since Babili will remove unused code before transpilation. It is much easier to spot unused classes before downleveled to ES5. Tree-shaking will also work for class declarations, not just functions.

You will need:

npm install babili babili-webpack-plugin --save-dev

Use the following plugin in your webpack config, like so:

plugins: [
  new BabiliPlugin()
]

There is also an optimzied way to use babili as a preset. You can refer their site to use it as a preset for babel-loader.