How to enable tree shaking for next.js?

Viewed 2220

Is there something to enable to have next.js perform tree-shaking/removal of dead code from dependencies? I've exported two objects like this:

library.js

export const foo = {foo:"foo"}
export const bar = {bar:"bar"}

And in my next.js app I do like this:

page.tsx

import { foo } from 'library';
console.log(foo);

So now I'd expect a production-build will not include bar, and indeed something appears to go right because this line is produced:

.next/server/chunks/621.js

/* unused harmony exports bar */

But confusingly when I load the app in the browser the network-traffic indicates the unused export is included:

http://localhost:3001/_next/static/chunks/pages/page-0b2b13a7513f2849d855.js

(self.webpackChunk_N_E = self.webpackChunk_N_E || []).push([[3031], {
    80621: function(e, r, n) {
        "use strict";
        ...
        const l = a.object({
            foo: "foo"
        });
        a.object({
            bar: "bar"
        });
    },

Why would the build identify unused exports but not remove them from the payload that's transferred to the browser? Is there a setting Next expects us to enable? Some sort of post-processing that actually prunes unused exports?

1 Answers

I believe the issue with your example is that Next.js is able to tree-shake primitive values (boolean, string, int,...) and object/array's with primitive values.

However, webpack, the bundler used in Next.js, isn't able to identify whether a function call has any side-effects.

From this Github Issue #12557, some users report that setting "sideEffects:false in the package.json or even modifying webpack in the next.config.js solved this issue.

None of those worked for me. Instead, marking function's as side-effect-free using the /*#__PURE__*/ annotation worked.

Example:

const createApi = (message) => {
  console.log(message);
  return () =>{}
}

export const serverApi = /*#__PURE__*/ createApi("I should only be available server side.")

export const clientApi = /*#__PURE__*/ createApi("I should only be available client side.")

Writing my code like above prevented serverApi from being included in the client bundle.

It should be noted, that the syntax of the annotation is /*#__PURE__*/ fn(). All other usages won't work.

Related