nx: Tree shaking problem (React Application and Library)

hi guys i have problem with tree shaking in nx,

problem with assets library

so i create an application let`s says its (main app) and i create a library called (assets)

index.js (assets library)

export { default as Logo} from './lib/Logo/';
export { default as Loading } from './lib/Loading/';

main.js (main apps)

import { Logo} from '@nx-test/assets';

export const Main= () => {
    return (
        <>
      <Logo/>
        </>
    );
};

export default Main;


nx build main --prod --buildLibsFromSource

when i bundle my main apps in dist/apps/main i have loading.(hash number).svg so why this loading get bundle?

and when i delete this code export { default as Loading } from './lib/Loading/';
on my assets index.js
loading.(hash number).svg not get bundle on dist folder

this problem also happen on my ui library and increase a lot of my bundle size

problem with ui library

index.js (ui library )

export { default as MyButton} from './lib/Button/Button';
export { default as MyModal } from './lib/Modal/Modal';

Button.js

import {Button} from 'antd'

export const MyButton =() =>{
    return (
        <Button/>
    }
};

Modal.js

import {Modal} from 'antd'

export const MyModal =() =>{
    return (
        <Modal/>
    }
};

Main.js

import {MyButton} from '@nx-test/ui';

export const Main= () => {
    return (
        <>
      <MyButton/>
        </>
    );
};

export default Main;

as you can see its only import button on main app, but when i remove export Modal on my index.js (entry file ui library) and now its only import button

export { default as MyButton} from './lib/Button/Button';

bundle size decrease 30kb

so why its happen? its like nx keep bundle all the third party (ant design modal) not what im using which is only button

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 11
  • Comments: 39 (5 by maintainers)

Most upvoted comments

We have the same problem in our nx monorepo. So for example we have an UI lib with many components. Each component has it’s own module file. And all modules are exported through the index.ts file of the lib.

When I now have an app and only import one module from the UI lib, all modules from the lib are included in the bundle after the build, even for the production build.

So one solution is to add path mapping in the root tsconfig.base.json for each module from the lib. Then only the need module is included in the build.

But maybe there is a nicer way? My colleague told me for publishable libs ng-packagr would do the magic. But since we have a monorepo we do not have any publishable lib. It would be nice if there would be some mechanism like for instance in the Angular Material library, where you can also import each module on it’s own to keep the bundle size low.

Closing this issue as we believe this to be resolved when we upgrade to Webpack 5.

Please reopen if you you believe this is still an issue.

Not to beat a dead horse, but I’m running into this as well on nx v14.

#3426 was an interesting read on the pros/cons of barrel files. I’m now questioning our use of them, despite their convenience. We have a react component component library with ~25 components exported in the barrel file.

Hi @maxime1992,

unfortunately it was working for the beginning but as more and more the project was growing with more libs it was not anymore working as in the beginning so we removed them back and waiting for the october release with webpack 5 support.

It is still ok if you cut your libs all in small peaces. So the recommendation is to use domain driven development to keep it them as small as possible and getting a rocket after webpack 5 and tree shaking is doing their job 😄

I’m also experience the same problem in my monorepo.

@conioX Did you found a solution?

Can agree but we are using angular, we just figured out that we have the same problem. So I think it is a common problem. But we found a solution 😃

Instead of using the index.ts in the tsconfig.base.json you can add all the index.ts files there

e.g:

"paths": {
      "@myworkspace/shared": ["libs/shared/src/index.ts"],
      ....
}

Change to:

"paths": {
      "@myworkspace/shared": [
           "libs/shared/src/module1/index.ts",
           "libs/shared/src/module2/index.ts",
           "libs/shared/src/module3/index.ts"
      ],
      ....
}

you still can use the import as before.

Try it out 😉 for us, it was working.

I’ve found a potential fix. See this answer which might resolve the issue of Webpack not properly tree shaking barrel files

@FrozenPandaz and team - this is a pretty big issue with NX, can we get some traction towards a resolution that doesn’t rely on workarounds such as the above?

any update on this? So far I’ve had no luck with this on v13.3.7 with webpack 5. I’ve tried the sideEffects: false solution and it appears to have no effect as the production bundle still includes all the modules in the library ):

What I was doing is have multiple components in shared lib and exporting all of them from index.js and the issue was all of them was getting added in the bundle even if I was using few of them. So the only solution I found was to not export the components from index.js rather import them like import componentName from components/componentName/componentName.tsx where components is my shared lib and inside that i had multiple folder for different components. I know it’s not a great approach but this solved my issue.

How can I achieve this? I tried to add the component path into tsconfig.base.json paths; vs code doesn’t show any errors on importing the default value but when I run the application it says

Cannot find module or its corresponding type declarations.