Today I Learned

React app bundle optimalization

As with any performance improvements, it’s important to have the tooling to evaluate if any changes provide value.


In case of React apps setup with CRA it is source-map-explorer non CRA users can use other tools like webpack-bundle-analyzer

browser devtools with network throttling Imgur

Step 1

Decide what’s the lowest network speed that need to work relatively fast. (I have picked fast 3G)

Step 2

Build the application as for production environment npm run build and then serve -s build -l 3002 in CRA or open the deployed app.

Step 3

Throttle the network and force load all resources without using cache CMD+Shift+R. If the application loads relatively fast, there might not be the need to split the code at all.

Step 4

Analyze generated bundle using source-map-explorer or webpack-bundle-analyzer (non CRA). Spot biggest/rarely used elements. In my case it was:

  • TinyMCE used in only one page
  • Lodash being included 3 times (lodash.js lodash.min.js lodash-es)
  • React-Player used only in a few pages
  • Translations (en and pl)
  • Constants contained some not needed data

Step 5

Tackle the biggest issues and evaluate the results (step 4)

  • Use React.lazy and Suspense to lazy load parts of the application
  • When doing manual webpack code splitting remember about defining shared dependencies
  • Check for babel transforms eg. babel-plugin-lodash
  • Some modules can be aliased lodash: 'lodash-es', so they are included only once.
  • Some packages offer optimization themselves eg. import ReactPlayer from 'react-player/lazy' lazy loading players for different video hostings.
  • Load translation files lazily using eg. i18next-xhr-backend

Details depend on every specific case.

Step 6

If tackling the biggest elements is not enough, continue splitting the app per route or group of routes accessible for different users. eg. split admin routes, regular user routes and not logged in guests routes.


Unless your application is gigantic, following all steps should be enough. In my case handling initial issues found in step 4 was enough.