How code splitting can make your React app load significantly faster
React-Loadable provides you with a component you can use to load a React component later, rather than immediately as you load the React app.
Why would I want to load a component later?
For example, lets say you've inherited a project from another engineer, and they've decided to use moment.js in one of the components.
The output of your webpack build gives you these chunk files, with the main one being 500kB. Of this massive bundle, 65.9kB belongs to the minified + gzipped moment.js library.
Since you're only using the component in a couple of places, it doesn't really make sense to load moment.js immediately as your users load your app. After all, they may not even use the component that uses moment.js!
If instead, you wrapped your component in Loadable
, your main bundle would be (roughly) 65.9kB smaller, and only the people that need your component that uses moment.js would download that bundle.
How do I use it?
First, install it:
yarn add react-loadable
or
npm install react-loadable
React-Loadable lets you wrap your massive component like this:
import Loadable from 'react-loadable';import Loading from './my-loading-component';
const LoadableComponent = Loadable({ loader: () => import('./my-massive-component'), loading: Loading,});
export default class App extends React.Component { render() { return <LoadableComponent />; }}
Resulting in a much smaller initial load time for your React app.
<LoadableComponent>
doesn't have to be in your App file, it can be anywhere in your component hierarchy.
Halving my React app's load time
Using the above approach was all I needed to shave 200KB from the main bundle of the performance monitoring tool I built (PerfBeacon).
Results:
Shaving 200KB off PerfBeacon's initial bundle reduced the TTI by more than half |
More specifically, I combined react-loadable
with react-router-dom
to split my bundle by the routes of my web app, resulting in a dozen or so Loadable components like this one:
// pages.jsexport default pages = { NotFound: Loadable({ loader: () => import('./NotFound'), loading: Loading, });}
While this is great for a start, there's still quite a bit more optimisation work to be done here.
Jamie has a much more in-depth explanation but essentially, any place with tabs, modals, or even low priority content at the bottom of a page can benefit from using react-loadable.
Conclusion
So that's how you can use react-loadable to massively speed up your react app.
Do you manually test your web performance? Do you wish you didn't have to? I'd love to help!
I built PerfBeacon.com to automatically test web performance after each deployment.
(Shameless plug for the useEffect book I wrote below)
Tired of infinite re-renders when using useEffect?
A few years ago when I worked at Atlassian, a useEffect bug I wrote took down part of Jira for roughly one hour.
Knowing thousands of customers can't work because of a bug you wrote is a terrible feeling. To save others from making the same mistakes, I wrote a single resource that answers all of your questions about useEffect, after teaching it here on my blog for the last couple of years. It's packed with examples to get you confident writing and refactoring your useEffect code.
In a single afternoon, you'll learn how to fetch data with useEffect, how to use the dependency array, even how to prevent infinite re-renders with useCallback.