Site Color

Text Color

Ad Color

Text Color





Sign Up to Save Your Colors


Effective Code Splitting in React: A Practical Guide by@aakashns

Effective Code Splitting in React: A Practical Guide

Aakash N S Hacker Noon profile picture

Aakash N S

Large bundle sizes and slow startup is a common problem faced by single-page applications (SPAs), since they typically download all the JavaScript required for every single page of the application right at the start, before rendering a single pixel.

A simple way to solve this problem is to use code-splitting i.e. breaking down the application’s JavaScript into small, modular bundles called chunks, which can be loaded on-demand when a particular feature is accessed. The goal is to keep individual chunks under 100–150 KB, so that the application becomes interactive within 4–5 seconds, even on poor networks.

Component-based code splitting

The open source library

provides a React-friendly API for code splitting, and lets you add breakpoints with just a few lines of code. If you're using
, Webpack automatically takes care of splitting the bundle and loading chunks on demand under the hood.

Here’s how it works: suppose we want to load and render the component

on demand, when the user clicks on a particular or navigates to a particular route. All we need to is wrap it using
as follows:

import Loadable from "react-loadable";
import Loading from "./Loading";

const AsyncSettingsPage = Loadable({
  loader: () => import("./SettingsPage"),
  loading: Loading

export { AsyncSettingsPage };

Now we can use

just like a normal React component. The module
s and its dependencies are no longer a part of the main JavaScript bundle and are loaded asynchronously when
is rendered for the first time.

While the chunk is loading, the component

g is rendered in its place. Here’s a sample implementation of

import React from "react";

const Loading = props => {
  if (props.error) {
    return <div>Error!</div>;
  } else {
    return <div>Loading...</div>;

export default Loading;

The prop

is set to a non-null value if the chunk fails to load.

Chunking multiple components together

There are some cases where simple component-based splitting may not be enough. For instance, you may have a set of components that are almost always used together in a several different features. In such a case, it makes sense to have a single chunk which contains the entire set of related components.

Here’s how we might normally export a set of related components:

import ItemListHeader from "./ItemListHeader";
import ItemListFilters from "./ItemListFilters";
import ItemListTable from "./ItemListTable";
export {

Assuming the above code is in the file

, we can create another file
with the following contents:

import React from "react";
import Loadable from "react-loadable";
import Loading from "./Loading";

const AsyncItemListHeader = Loadable({
  loader: () => import("./index").then(m => m.ItemListHeader),
  loading: Loading

const AsyncItemListFilters = Loadable({
  loader: () => import("./index").then(m => m.ItemListFilters),
  loading: Loading

const AsyncItemListTable = Loadable({
  loader: () => import("./index").then(m => m.ItemListTable),
  loading: Loading

export {

The key change here is in the dynamic

: instead of importing a single component, we are importing all of
and extracting the required component in the promise callback.

Chunk naming and optimization

When we build application for production after implementing code splitting, we get many chunks of Javascript that look like this:

File sizes after gzip:  396.71 KB              build/static/js/main.3a8842c0.js
  178.51 KB              build/static/css/main.e32b4522.css
  68.31 KB               build/static/js/6.af93367f.chunk.js
  44.34 KB               build/static/js/2.6a7f1417.chunk.js
  23.61 KB               build/static/js/1.bdfdcd83.chunk.js
  22.24 KB               build/static/js/3.d9e4ee99.chunk.js
  19.29 KB               build/static/js/4.a66b3cdb.chunk.js
  17.1 KB                build/static/js/5.f1ce26f7.chunk.js
  7.63 KB                build/static/js/8.2e807534.chunk.js
  6.71 KB                build/static/js/9.409015da.chunk.js
  5.09 KB                build/static/js/7.1b95d8e8.chunk.js
  1.71 KB                build/static/js/0.6bea2af7.chunk.js
  1 KB                   build/static/js/10.ce9f2434.chunk.js

After looking at this output, we might want to remove some of the last few chunks since they’re really small. But we don’t know which split is causing which chunk to be created. This is where chunk naming can be helpful.

We can use a magic comment inside the

t that tells Webpack to use the given name for a specific chunk:

const AsyncSettingsPage = Loadable({
  loader: () => import("./SettingsPage" /* webpackChunkName: "settings" */),
  loading: Loading

Once all the chunks are named, we can identify the splits that lead to smaller chunks:

File sizes after gzip:  312.09 KB  build/static/js/main.491eaaf4.js
  181 KB      build/static/css/main.ac06cedb.css
  68.88 KB   build/static/js/settings.1525d075.chunk.js
  45.08 KB   build/static/js/alerts.0f5ad4d6.chunk.js
  23.62 KB   build/static/js/profile.199c7f90.chunk.js
  22.24 KB   build/static/js/history.07ccea31.chunk.js
  19.3 KB    build/static/js/actions.903378a5.chunk.js
  8.87 KB    build/static/js/events.f540de3a.chunk.js
  7.62 KB    build/static/js/colors.89aa1e6f.chunk.js
  6.7 KB     build/static/js/posts.929f04fc.chunk.js
  5.1 KB     build/static/js/post-details.6c133f77.chunk.js
  1.71 KB    build/static/js/friend-list.be516e45.chunk.js
  1.01 KB    build/static/js/edit-avatar.33a4ff21.chunk.js

At this point, we can choose to remove or combine some of the smaller chunks (< 20–30 KB in size), since the overhead of loading a 5 KB chunk might be higher than combining it with one of the larger chunks. Play around with different splits and see what works best for you.

Analyzing the Bundle Size

Source map explorer analyzes JavaScript bundles using the source maps. This helps you understand where code bloat is coming from. To add Source map explorer to a Create React App project, run the following command:

npm install --save source-map-explorer

Then in

, add the following line to

"scripts": {
    "analyze": "source-map-explorer build/static/js/main.*",

Then to analyze the bundle run the production build then run the analyze script.

npm run build
npm run analyze

Source map explorer

Look for the largest contributors to the bundle size as possible candidates for code-splitting. Also consider removing or pruning large dependencies from



Here are steps for achieving effective code splitting in React applications:

  • Use
    to achieve component-based code splitting and load Javascript bundles for different parts of the application on demand.
  • Chunk multiple components that are frequently used together into a single file using the
  • Name your chunk using the magic comment
    /* webpackChunkName: xxx */
    and optimize bundle sizes so that they are neither too small nor too large.
  • Use
    to identify possible candidates for code splitting.

I’ve skipped over many details to keep this article short and focus on the practical aspects of code splitting. Following are some good places to learn more about the topic: