question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

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

See original GitHub issue

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!

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:11 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
cspotcodecommented, Mar 26, 2016

@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.

1reaction
TheLarkInncommented, Sep 2, 2016

It does. Webpack can mark unused imports/exports, (see usedExports property on HarmonyExportSpecifierDependency (I believe)), however it’s simply marking the statements and specifiers. Is it possible, maybe, but would be extremely complex and time consuming. We believe that a generic tool should be passed an AST program, to assist in analyzing and optimizing (and used/implemented in Webpack similar to UglifyJsPlugin) that any bundler etc can use. (Like babili, but more than just ES6 I think)

We’d love to have help from Flow, TS, babili, esprima, acorn, uglify, whatever, and framework teams to make one unifying tool to that can provide a High Level general purpose static program flow analysis optimizer/minifier. I know each library, parser has separate needs, but I think there could be a high-level approach at some of this, and benefits everyone.

/cc @hzoo @gaearon @danielrosenwasser @wycats @igorminar @Rich-Harris @aryia

My super super high level thoughts:

Tool takes ES6(or mixed commonjs, etc whatever is possible)AST/Program, tool does optimization, returns either optimized AST Program for respective parsers/compilers/etc to use.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Tree Shaking - webpack
Tree Shaking. Tree shaking is a term commonly used in the JavaScript context for dead-code elimination. It relies on the static structure of...
Read more >
How Tree-shaking in JavaScript Bundlers work
Tree shaking is a technique used in dead code elimination which aims to reduce bundle size by removing unused functions, imports and statements...
Read more >
Tree shaking and code splitting in webpack - LogRocket Blog
Tree shaking, also known as dead code elimination, is the practice of removing unused code in your production build.
Read more >
Does Webpack tree shaking with dead code elimination work ...
I was expecting that tree shaking alongside with dead code elimination of UglifyJS should work in a way that enables me to write...
Read more >
How to make your library tree-shakable - Level Up Coding
Tree shaking is a term commonly used in the JavaScript context for dead-code elimination. Although many bundlers nowadays support tree-shaking like Rollup ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found