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.

Bundle Size issues caused by Webpack failing to tree-shake

See original GitHub issue

Bug report

We noticed bundle size issues in our Next.js application. More specifically we noticed that basically all of the code served on all routes, even though most of it was not needed.

After hours of debugging I finally managed to find the line of code responsible for this behaviour…

Describe the bug

Webpack is failing to tree-shake Components with static properties.

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Clone https://github.com/MrAvantiC/next-tree-shaking-issues
  2. Run npm run build && npm start
  3. Visit localhost:3000
  4. Open network tab and see contents of index.js
  5. You will find the following Code:
        var O = function(t) {
            p(e, t);
            var n = _(e);
            function e() {
                var t;
                i(this, e);
                for (var r = arguments.length, o = new Array(r), c = 0; c < r; c++)
                    o[c] = arguments[c];
                return v(l(t = n.call.apply(n, [this].concat(o))), "withStaticFunction", (function() {
                    console.log("withStaticFunction")
                }
                )),
                t
            }
            return a(e, [{
                key: "render",
                value: function() {
                    return S("h1", null, "TestWithStatic")
                }
            }]),
            e
        }(r.Component);
        v(O, "defaultProps", {
            foo: "bar"
        });
  1. Stop Server, open components/TestWithStatic/index.js and delete line 4 static defaultProps = { foo: 'bar' }
  2. Repeat steps 2 to 4 and you will see, that the unused Component has now been correctly tree shaken.

Expected behavior

Unused Components should always be excluded from the bundle

System information

  • Version of Next.js: 9.3.6

Additional context

I found a couple of related issues:

Webpack closed the issue saying:

Does this mean webpack has no intention of changing this behavior in the future?

webpack is not doing the Dead-Code-Elimination. It’s done by uglify-js2 (webpack 4) or terser (webpack 5). If you want this behavior changed, that’s where to look.

Anyway, I’m going to fix this for our project, but maybe Next.js should guide users here and fix this issue by default, however the fix may look like…

Issue Analytics

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

github_iconTop GitHub Comments

1reaction
mattcarlottacommented, May 10, 2020

Not super knowledgable about compilation methods, but it appears that React elements are being assigned (not by an identifiable name), but are just never utilized. When using a static reference, it appears to transform the code differently, but again still not utilized.

For example, look at how many times createElement is assigned to a variable:

With sideEffects (4):

n.d(e, 'default', function () { return S  }) // default parent export (index.js)

var r = n('q1tI'), o = n.n(r), c = o.a.createElement

function u(t) { return c('h1', null, 'TestComponent') } // child component

var d = o.a.createElement // never utilized

var _ = o.a.createElement  // never utilized

var R = o.a.createElement // parent component (index.js)

function S() { return R(u, null) }

Without sideEffects/direct imports (2):

 e.d(t, 'default', function () { return s }) // default parent export (index.js)

var r = e('q1tI'), u = e.n(r), o = u.a.createElement

function i(n) { return o('h1', null, 'TestComponent') } // child component

var c = u.a.createElement // parent component (index.js)

function s() { return c(i, null) }
1reaction
mattcarlottacommented, May 10, 2020

This isn’t a problem with Next, nor does it stem from class properties, but the problem comes from this file. Webpack doesn’t tree shake this file properly because it’s not sure if it has side effects or not. You can mark it as side effect free by including this in your package.json file:

{
  name: "example",
  sideEffects: false, // alternatively you could specify an array of files
  scripts: { ... },
  dependencies: { ... },
  devDependencies: { ... }
}

However, this may not be the case for all your files, and specifying which does or doesn’t have side effects may be cumbersome, so alternatively you may want to restructure your imports to be direct:

import Example from "./path/to/Example";

Results

Not marked as side-effect free:

Marked as side-effect free:

Direct import:

Read more comments on GitHub >

github_iconTop Results From Across the Web

Bundle Size issues caused by Webpack failing to tree-shake
Describe the bug. Webpack is failing to tree-shake Components with static properties. To Reproduce. Steps to reproduce the behavior, please ...
Read more >
Webpack 4 tree shaking - Marcin Wanago Blog
Webpack 4 course – part seven. Decreasing the bundle size with tree shaking; 8. ... Unfortunately, webpack will still fail to tree shake....
Read more >
Why webpack doesn't tree-shake the lodash when using ...
This uses Babel to rewrite your lodash imports into a more tree-shakeable form. Doing this dropped my team's bundle size by ~32kB (compressed) ......
Read more >
Tree Shaking - webpack
While that may not seem like much in this contrived example, tree shaking can yield a significant decrease in bundle size when working...
Read more >
How to Fully Optimize Webpack 4 Tree Shaking | by Craig Miller
In our department, the biggest problem was a number of shared libraries. ... you need the whole library, and Webpack will not tree...
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