nx: Production build tree shaking not working
Tree shaking does not work. I created a React app with both Nx and create-react-app, and imported a single lodash function.
Current Behavior
Nx bundle:

Expected Behavior
Create react app bundle:

Steps to Reproduce
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import styles from './app.module.scss';
import NxWelcome from './nx-welcome';
import { get } from 'lodash-es';
export function App() {
console.log(get({ foo: true }, 'foo'));
return (
<>
<NxWelcome title="lodash" />
<div />
</>
);
}
export default App;
Environment
> NX Report complete - copy this into the issue template
Node : 16.13.2
OS : darwin x64
npm : 8.1.2
nx : 13.9.7
@nrwl/angular : Not Found
@nrwl/cypress : 13.9.7
@nrwl/detox : Not Found
@nrwl/devkit : 13.9.7
@nrwl/eslint-plugin-nx : 13.9.7
@nrwl/express : 13.9.7
@nrwl/jest : 13.9.7
@nrwl/js : 13.9.7
@nrwl/linter : 13.9.7
@nrwl/nest : Not Found
@nrwl/next : Not Found
@nrwl/node : 13.9.7
@nrwl/nx-cloud : Not Found
@nrwl/nx-plugin : Not Found
@nrwl/react : 13.9.7
@nrwl/react-native : Not Found
@nrwl/schematics : Not Found
@nrwl/storybook : 13.9.7
@nrwl/web : 13.9.7
@nrwl/workspace : 13.9.7
typescript : 4.4.4
rxjs : 7.5.4
---------------------------------------
Community plugins:
@nx-tools/nx-docker: 2.3.0
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 15 (1 by maintainers)
A full solution that worked for me. Nx version: 13.10.2
apps/<app>/project.jsonapps/<app>/custom-webpack.config.jspackage.jsonIf your app has side effects, for example, global styles, you need to specify an array of effectful files in the
package.json:I didn’t have problems with Jest or
"target": "es2015"in thetsconfig.base.jsonfile as described in the comment above.Tree shaking does not work for me on a freshly installed nx workspace using Webpack and Babel.
Reproduce issue
npx create-nx-workspace@latest monoreponpx nx generate @nrwl/react:application shell --bundler=webpack --compiler=babel --unitTestRunner=jest --e2eTestRunner=noneImport a library which exports a barrel file. I’ll use
date-fnsas an example. Open theAppcomponent of the newly generated React application and import a function fromdate-fns:Now let’s look at both the development and production builds in
dist/apps/shell/main[.id].jsbuild and see what happened.Development build
date-fnsfunctions are imported. Notice the import in the main bundle:Production build
date-fnsfunctions are importedYou should see something like:
The fix
I did some extensive digging and managed to solve the issue by extending/overriding the default webpack config:
You will now see that the module is concatenated and only the required date functions are imported:
Full code of
webpack.config.js:After altering the Webpack configuration, the bundle size went from
900kbto a mere140kb🥳Tree shaking lodash
Tree shaking lodash by using named imports (i.e.
import { set } from "lodash") still didn’t work for me as lodash exports its barrel file as CJS. There are three ways to fix this that I know of:import set from "lodash/set"lodash-esas it exports ES modules instead of CJSUsing Vite
I can confirm that tree shaking and minification does work out-of-the-box on a fresh workspace using Vite + SCW. For some this might be the way to go. In my case, however, I need Webpack as I want to experiment with Module Federation.
Got it! In my case simply adding to package.json made me get the desired result, I did as you said and I got no difference from just adding it to the package.json. I think it’s because webpack already takes the package.json sideeffect into consideration
https://webpack.js.org/guides/tree-shaking/
But either way this was a great find! Thanks a lot
https://webpack.js.org/configuration/optimization/#optimizationsideeffects
By logging out the webpack configs that nx is using, I see it has
optimization: { sideEffects: false }. Is there a reason this is turned off?Additionally, Nx has my tsconfig.json set to
"target": "es2015",.I fully expect both of these issues to prevent tree shaking.
After I fixed both of these issues, I can confirm Nx properly tree shakes 👍 . All I did was:
(see https://nx.dev/guides/customize-webpack)
and in
tsconfig.base.jsonI set"target": "esnext",😃In turn these changes break Jest, to fix this I added
jest.preset.js:
babel.config.json:
And now jest works again
After making these changes and switching branches
nx buildalso broke with this:After
rm -fr node_modules/.cachethis error was also resolved, and is tracked in a separate bug I reported here https://github.com/nrwl/nx/issues/9662@LeonardoGobbiLopez Thank you! 🎉 the webpack
optimization.sideEffects: truechange was exactly what I was missing.That was not my experience. In my original issue report, I found that Nx is passing
optimization: { sideEffects: false }to webpack, which explicitly turns off tree shaking regardless of your package.json contents. The library that was not being tree shaken in my original issue (lodash-es) already has it’s ownpackage.jsonwhere it specifies the required setting to facilitate optimal tree shaking, however Nx was turning off tree shaking in Webpack globally, so that it doesn’t happen at all for any library or any code in the project.Actually you only need to add the
"sideEffects": falseto the package.jsonAlso thanks a lot for the response, it helped me a lot!