In this blog, we will try to understand what code splitting is and
why we should implement it. With Code splitting, we can reduce the
initial bundle size, app loading time, and enhance its performance
and optimise our code.
When we create an application, we write code in several files. It
includes many modules and third-party libraries. When we build, it
converts these many files into a single large file(bundle), well,
not literally, but for understanding, yes. And this bundle is used
by a web browser to load the application.
Initially, when our application is small, the bundle size is small.
As the application grows and becomes more complex, the bundle size
grows simultaneously. And the bigger the bundle size is, the more
time it takes for the application to load. Therefore, we can say
that a bigger bundle size is an issue and affects the application
performance.
Now, what if there is a definite way to load the necessary files to
start the application and later load other files, as well, when
required. This way, we can keep our initial bundle size small and
get our applications to load faster.
React has this feature, It is called Code-Splitting. Code splitting
is a way/feature to split up your code from a large file or
component into various bundles. These can then be requested on
demand or in parallel. Some common use cases of code/bundle
splitting and lazy loading, are:
- As the user moves to a new view of the application, you can lazy
load more code. -
Loading may also be tied to a particular movement, such as
scrolling or pressing a button. -
You might also try to guess what the user would try to do next and
load the code accordingly. -
As the user attempts to access the functionality, it will already
be there. Now we’ll see how code splitting works and how you can do
it well.
Code Splitting in a React Codebase
Some common ways to do code splitting are listed below:
1. Dynamic imports using Webpack
Webpack allows you to import modules during runtime dynamically.
Here is an example. Whenever we import a module or third party
library, we generally import it like this and it imports the file in
a synchronous way.
import { homeComponent } from './home;
It means that the initial bundle file will have this import. Here
comes the dynamic import method to import files asynchronously.
import('./home).then(home => { console.log(home.renderHome())})
This syntax will let the Webpack file that’s to be code split and
bundled be generated accordingly.
2.Using React.lazy and React.Suspense
Another way of splitting the code is using the React.lazy()
method.This is a feature provided directly by React. This function
lets you render a dynamic import as a regular component. It means
that we can define components that can be imported dynamically in
the application. This helps us reduce the bundle size because we are
delaying the loading of the component that might be used later in
the application. Let’s understand this by an example.
import React, { useState } from 'react'; import homeComponent from './home;
export default function App() {
const [showDetails, setShowDetails] = useState(false);
return (
<>
<h1>Home</h1>
<button onClick={() =>
setShowDetails(true)}>Show Details
</button>
{showDetails ? <homeComponent /> : null }
</>
)};
As we can see in the above example that component homeComponent will
only render when the user clicks on the button Show Details. Here we
can use lazy loading to load the component homeComponent. Let’s do
it with the help of React.lazy().
This method takes a function that calls a dynamic import().
const ProjectDetails = React.lazy(() => import('./home));
But there is a catch, what if our import takes time to load? The
React.Suspense comes into the picture. The lazy component is always
used within the Suspense component. It allows us to specify loading
indicators as fallback content until our lazy component is ready to
render.
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div> <Suspense fallback={<div>Loading...</div>}>
<OtherComponent /> </Suspense> </div>
)}
The fallback props take any React
element that we want to show while the lazy component is loading.
You can also use a single Suspense component to wrap several lazy
components.
import React, { Suspense } from 'react';
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
function MyComponent() {
return (
<div> <Suspense fallback={<div>Loading...</div>}>
<OtherComponent /> <AnotherComponent /> </Suspense> </div>
)}
3.Route Level Splitting
Now we know how to split our code to reduce the bundle size, so we
can do it in the application so it doesn’t hinder the way the user
interacts with the application.
Therefore, routes are a good place to start with because generally,
users are familiar with delays when they transit from one route to
another.
Let’s see how we can set up route-based code splitting into your app
using libraries like React Router with React.lazy.
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from "./home";
const Profile = lazy(() => import('./profile'));
const ContactUs = lazy(() => import('./contact'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/profile" element={<Profile />} />
<Route path="/contact" element={<ContactUs />} />
</Routes>
</Suspense>
</Router>
);
To read more about code-splitting, please check official
React documentation.