Code Splitting in React
As an application grows in complexity, files or bundles grow in byte size. Code splitting is the splitting of code into various bundles or components which can then be loaded on demand or in parallel.
ES Modules are completely static which means that you must import the module at compile time not run-time. The import may only appear at the top level of the component that is doing the importing.
What code splitting does is import at run-time based on some condition. That condition can be a route that you’re calling or an if statement you’re executing.
Let’s illustrate code splitting with a React Application:
$> npx create-react-app my-app --template typescript
Install react router
$> npm i react-router-dom
Let’s now create a multi route app
import './App.css';
import { BrowserRouter, Link, Route, Routes } from 'react-router-dom';
import Home from './Home'
import About from './About'
import Contact from './Contact'
function App() {
return (
<BrowserRouter>
<div className="App">
<ul className="nav" >
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact Us</Link></li>
</ul>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
When we build the app,
$> yarn build
we see that our code is built to 2 js files and a css file.
File sizes after gzip:
50.5 kB (+4.12 kB) build/static/js/main.7b3d5e9b.js
1.75 kB build/static/js/27.c0530718.chunk.js
561 B (+20 B) build/static/css/main.8be8f408.css
Let’s add code splitting. Once we code split we’ll see a lot more chunks that will enable the browser to download component chunks on demand. So to code split components used as route elements, we need to change the import statements to use React.lazy
import React from 'react'
import './App.css';
import { BrowserRouter, Link, Route, Routes } from 'react-router-dom';
const Home = React.lazy(() => import('./Home'))
const About = React.lazy(() => import('./About'))
const Contact = React.lazy(() => import('./Contact'))
function App() {
return (
<BrowserRouter>
<div className="App">
<ul className="nav" >
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact Us</Link></li>
</ul>
<React.Suspense fallback={<p>Loading...</p>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</Suspense>
</div>
</BrowserRouter>
);
}
export default App;
In addition to lazy importing, we need to wrap the implementation of the lazy component with a React.Suspense component to show “loading HTML” as components are injected.
We build again, and we now see more chunks:
File sizes after gzip:
50.56 kB (+22 B) build/static/js/main.de3c9d11.js
1.75 kB build/static/js/27.c0530718.chunk.js
561 B build/static/css/main.8be8f408.css
222 B build/static/js/530.270422f6.chunk.js
217 B build/static/js/854.31ebed93.chunk.js
217 B build/static/js/610.cfe506f7.chunk.js
Code splitting works nicely to split route components, however you may choose to split where ever you have heavy code.