webpack: Tree shaking not working for functions executed in JS file when compared with Rollup

Do you want to request a feature or report a bug?

This is a bug where the same project can tree shake and remove unused code when bundled with Rollup but it does not when bundle is generated with webpack 2. To replicate and give an example I have created a repo to replicate this bug https://github.com/ankurp/rollup-webpack-test/

What is the current behavior?

Webpack 2 should remove code that is not used even if a function or class defined in a JS file gets executed. For example the following code below should remove the square function and the getSquare function which it does when bundled with Rollup but when bundling with Webpack 2 it includes getSquare because that function is invoked in the math.js file. This is the wrong behavior when compared with rollup which removes that unused function as well.

// math.js
function getSquare() { return x => x * x; }
export const square = getSquare();
export const cube = x => x * x * x;

// index.js
import { cube } from './math';
console.log(cube(3));

If the current behavior is a bug, please provide the steps to reproduce.

Best way to reproduce is to run yarn and then yarn build in this repo https://github.com/ankurp/rollup-webpack-test/

The repo has three basic JS files to replicate this bug and also generates both rollup and webpack output for comparison with optimized compressed builds on which tree shaking is performed.

What is the expected behavior?

Webpack 2 should remove getSquare function from the bundle as it is not imported or used.

If this is a feature request, what is motivation or use case for changing the behavior?

This is a bug that needs to be fixed so that the tree shaking feature works as expected.

Please mention other relevant information such as the browser version, Node.js version, webpack version and Operating System.

This was run using webpack 2.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 15
  • Comments: 17 (3 by maintainers)

Most upvoted comments

+++++++++++++ 1

@TheLarkInn

I believe this can be closed since it should be fixed in webpack 4 (see above).

I use explicit /*#__PURE__*/ as a workaround.

const _square = /*#__PURE__*/ function getSquare () { return x => x * x; }()
export const square = _square

@ankurp: I added a manifest chunk to strip out the webpack runtime. When I run your example with webpack 2.2.0 (as you use in your repo), I get the following output, which represents the bug you’ve reported:

webpackJsonp(
  [0, 1],
  [
    function(n, t, r) {
      "use strict";
      r(1);
      r.d(t, "a", function() {
        return u;
      });
      var u = function() {
        return 1;
      };
    },
    function(n, t, r) {
      "use strict";
      function u() {
        return function(n) {
          return n * n;
        };
      }
      var e = (u(), function(n) {
        return n * n * n;
      });
      e(3);
    },
    function(n, t, r) {
      "use strict";
      Object.defineProperty(t, "__esModule", { value: !0 });
      var u = r(0);
      console.log(r.i(u.a)());
    }
  ],
  [2]
);

With webpack 2.4.1, I get the following output:

webpackJsonp(
  [0],
  [
    function(n, t, e) {
      "use strict";
      e(2);
      e.d(t, "a", function() {
        return u;
      });
      var u = function() {
        return 1;
      };
    },
    function(n, t, e) {
      "use strict";
      Object.defineProperty(t, "__esModule", { value: !0 });
      var u = e(0);
      console.log(e.i(u.a)());
    },
    function(n, t, e) {
      "use strict";
    }
  ],
  [1]
);

Update to the latest version of webpack and have another go.

With that said, rollup’s generated bundle contain less even with 2.4.1, so there is definitely room for improvement.