Nx: Tree shaking problem (React Application and Library)

Created on 25 May 2020  路  6Comments  路  Source: nrwl/nx

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

react bug

Most helpful comment

We have the same problem in our nx monorepo. So for example we have an UI lib with many components. Each component has it鈥檚 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鈥檚 own to keep the bundle size low.

All 6 comments

run on latest @nrwl/nx 9.3.0

Hi, thank you for the details to reproduce. It would help us help you if you went 1 step further and provided a repo we could pull down and see the issue! Could you please provide a repo if you have time?

Thanks for your response @FrozenPandaz

i create a repo you can pull it here :
https://github.com/conioX/nx-assets-ui

on this repo :

2 main apps :

main-assets (assets test case)
main-ui (ui test case)

2 libs :

assets
ui

on libs (ui) entry file index.js

export * from './lib/NxButton/NxButton';
//uncomment this below code (NxModal) to test tree shaking
//export * from './lib/NXModal/NXModal';

information

nx build main-ui --prod --buildLibsFromSource
nx build main-assets --prod --buildLibsFromSource

this below image if we commnet nxModal on libs ui entry file index.js.
main.(hash number).esm.js = 76.1kb

2

this below image if we uncommnet nxModal on libs ui entry file index.js.
main.(hash number).esm.js = 95.6kb increase 20kb

1

its like nx bundle 3rd library (ant modal), test on disable cache (chrome)

@conioX Did you found a solution?

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

We have the same problem in our nx monorepo. So for example we have an UI lib with many components. Each component has it鈥檚 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鈥檚 own to keep the bundle size low.

Was this page helpful?
0 / 5 - 0 ratings