Webpack-2 recursive tree-shaking/dead code elimination.

Hello, i’ve been trying out webpack@2.0.7-beta and noticed that webpack doesn’t eliminate dead code recursively. Let me show you an example:

import { otherFunc1, otherFunc2 } from './otherModule';

function callOther() {
  otherFunc1();
  otherFunc2();
}

export default function () {
  if (process.env.NODE_ENV !== 'production') {
    callOther();
  }
}

Let’s say process.env.NODE_ENV === 'production', so the condition is always false.

  1. I would expect the whole if block in default function to be stripped out.
  2. So callOther would get stripped out.
  3. So otherFunc1 and otherFunc2 would get stripped out(they aren’t used anywhere else).

Webpack does steps 1 and 2, but skips step 3, so otherFunc1 and otherFunc2 end up in the bundle anyway.

If i call otherFunc1 and otherFunc2 directly inside the if block, they don’t end up in the bundle.

My webpack.config.js:

'use strict';

var webpack = require('webpack');

var env = process.env.NODE_ENV;

var config = {
  module: {
    loaders: [
      { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }
    ]
  },
  output: {
    library: 'bundle',
    libraryTarget: 'umd'
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(env)
    })
  ]
};

module.exports = config;

My .babelrc:

{
  "plugins": [
    ["transform-es2015-template-literals", { "loose": true }],
      "transform-es2015-arrow-functions",
      "transform-es2015-shorthand-properties",
      ["transform-es2015-computed-properties", { "loose": true }],
      "check-es2015-constants",
      ["transform-es2015-spread", { "loose": true }],
      "transform-es2015-parameters",
      ["transform-es2015-destructuring", { "loose": true }],
      "transform-es2015-block-scoping",
      "transform-object-rest-spread",
  ]
}

And i call webpack with:

cross-env NODE_ENV=production webpack -p src/index.js dist/bundle.min.js"

Thanks!

Author: Fantashit

1 thought on “Webpack-2 recursive tree-shaking/dead code elimination.

  1. @le0nik I think I know why this happens.

    As I understand it, webpack does dead code elimination in two steps. First it figures out which exports are being referenced, and it writes the chunk’s code, only assigning exports to the exports object if they’re “used” somewhere. Then it passes that code to UglifyJS, which removes dead code.

    1. I would expect the whole if block in default function to be stripped out.
    2. So callOther would get stripped out.
    3. So otherFunc1 and otherFunc2 would get stripped out(they aren’t used anywhere else).

    Numbers 1 and 2 are handled by UglifyJS. Number 3 is handled by webpack. However, since webpack is doing its part before UglifyJS, it doesn’t know it can remove those functions.

    If i call otherFunc1 and otherFunc2 directly inside the if block, they don’t end up in the bundle.

    I think you’re just getting lucky here because webpack ignores code inside false conditionals. It doesn’t, however, remove that code; it waits for Uglify to take care of that.

Comments are closed.