Search code examples
reactjstypescriptbundlewebpack-5

Re-exports not properly bundled with Webpack 5


When bundling my web-application, I have realised that re-exports of (some) modules do not work as expected. I have tried multiple optimization settings but so far with no success.

Setup

So basically I have the following setup

config/
  webpack.config.ts
  package.json

frontend/
  apps/
    app1/
      src/
        index.tsx
        App.tsx
        ...
  packages/
    test/
      index.ts
      testFunc.ts
      test1Func.ts
      Test.tsx
      Test1.tsx

So I run webpack from config with the entry point frontend/apps/app1/index.tsx which imports App.tsx (standard React application).

This all works fine but I have realised that when produce a production build from app1, unused exports in my App.tsx appear in the bundle. To clarify

import { testFunc } from 'packages/test' // <- `packages` is an alias

const App: React:FC = () => {
  const t = testFunc();
  return <>Hello World!</>;
}

will include Test.tsx, Test1.tsx and 'test1Func.ts' in the bundle. My index.ts in test/ looks like

export { testFunc } from './testFunc';
export { test1Func } from './test1Func';
export { Test } from './Test';
export { Test1 } from './Test1';

I should mention that testFunc1.ts contains a useEffect hook because I found that as soon as I have react related code, there is no tree shaking for the source anymore. So

// test1Func.ts
export const test1Func = () => {
  useEffect(() => {
    // do nothing
  }, []);
  return "Test 1";
}

However, if I import my files directly, eg. import { testFunc } from 'packages/test/testFunc', everything works as expected and only test appears in the bundle. This also applies to the other test components:

App import tests

testFunc

  • import via index.ts & use in App.tsx => bundles all files inside test/
  • import via import { testFunc } from 'packages/test/testFunc' & use in App.tsx => only testFunc.ts is included in the bundle ✅
  • import via import { testFunc } from 'packages/test/testFunc' & don't use in App.tsx => nothing gets included in the bundle ✅

testFunc1 | TestTest1 <- they all behave the same

  • import via index.ts & use in App.tsx => bundles all but testFunc
  • import via import { test1Func } from 'packages/test/test1Func' & use in App.tsx => only test1Func.ts is included in the bundle ✅
  • import via import { test1Func } from 'packages/test/testFunc' & don't use in App.tsx => nothing gets included in the bundle ✅

I guess this is just a configuration error, although I have already tried multiple different optimisation settings. The closest probably is the sideEffects option but so far, this also did not have any effect.

Any ideas?

Thank you very much!


Solution

  • I found the solution! 🙌

    As guessed, I had Webpack's optimization.sideEffects property misconfigured. sideEffects is necessary for proper tree shaking.

    However, in order to get this work properly there are 2 destinations where you have to set the sideEffects property:

    • your package.json (in my case in every package I use in my monorepo)
    • and in the webpack.config.ts
    Solution

    The admittedly very confusing thing is that you will have to set

    • sideEffects: false in the package.json
    • and sideEffects: true in the optimization section in your webpack.config.ts

    Here's a bit more if you are interested.