Back

/ 4 min read

How to Make your React App Load 10x Faster - Code Splitting

Context: This article is about code splitting. There are many other performance techniques that we would be using throughout the series. Starting with code splitting, as for basic implementation, it can be easily done by adding dynamic imports.

We’ll be using the site CatPrep.in as our example for the same.

What is Code Splitting and why is it required?

To understand why code splitting helps, it’s important to recap the basic client-server architecture of the web.

Client Server Architecture

So, the client makes a call to the web server, which then sends over the initial HTML file to the browser. This HTML file is then parsed by the browser, and when it encounters other linked files (say, CSS, JS, images, etc.), it makes additional calls to the server to fetch them.

The Problem: The Monolithic Bundle

We will focus on the JS file going forward to understand code splitting. By default, Single Page Applications (SPAs) like React, Angular, Vue, etc., compile all the code into a single, massive JS bundle file. Depending on the size of the application, this file could be HUGE!

Let’s illustrate this with some numbers. Imagine our CatPrep.in application, before code splitting.

  • Initial Bundle Size: 2.5 MB (This includes all the code for the Home Page, Question Page, Store Page, Discussion Page, and Profile Page.)
  • Time to Download (on a slow 3G connection): ~20 seconds
  • Time to Parse: ~5 seconds

That’s a whopping 25 seconds before the user sees anything meaningful! This is a terrible user experience.

This is the Single Page Application paradigm, where we ship an almost empty HTML page. This page is then populated by the JavaScript that is parsed in the Client Browser.

So, to solve this issue of downloading a large JS file initially (where some of the code may not be immediately required) and parsing it, we can split our JS code out logically based on use cases. This is what we call Code Splitting.

Analogy: The Delivery Truck vs. The Fleet

Think of your entire JavaScript bundle as a giant delivery truck carrying everything your application needs. This truck has to travel from the server to the user’s browser before anything can be delivered.

Code splitting is like replacing that single giant truck with a fleet of smaller, more specialized delivery vehicles.

  • Instead of one truck carrying everything, we have smaller vans that only carry what’s needed for the current page.
  • When the user navigates to a new page, a new van is dispatched, only carrying the code for that specific page.

Example: CatPrep.in with Code Splitting

In our CatPrep.in website, a user might just visit the Home Page and do a couple of questions on the Question Page. In this example, there is no need to delay the initial render by downloading and parsing code for other flows like the Store Page, Discussion Page, and Profile Page.

Here’s how code splitting can improve our example:

  • Home Page Bundle: 500 KB (Only the code needed for the Home Page)
  • Question Page Bundle: 700 KB (Only the code needed for the Question Page)
  • Store Page, Discussion Page, Profile Page Bundles: Loaded only when the user navigates to those pages.

Now, the initial download is much smaller, and the user sees the Home Page much faster.

  • Initial Load Time (Home Page): ~4 seconds download + ~1 second parse = 5 seconds.

This is a significant improvement!

How to Implement Code Splitting in React

React provides a few ways to implement code splitting:

  1. Dynamic Imports: The easiest way to code split is by using dynamic import() syntax. This allows you to load components lazily.

    import React, { Suspense } from 'react'
    const HomePage = React.lazy(() => import('./HomePage'))
    function App() {
    return (
    <Suspense fallback={<div>Loading...</div>}>
    <HomePage />
    </Suspense>
    )
    }
    • React.lazy() takes a function that must call a dynamic import().
    • Suspense is used to display a fallback UI (like a loading spinner) while the component is being loaded.
  2. Route-Based Code Splitting: If you’re using React Router, you can code split your routes.

    import React, { lazy, Suspense } from 'react'
    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
    const HomePage = lazy(() => import('./HomePage'))
    const QuestionPage = lazy(() => import('./QuestionPage'))
    function App() {
    return (
    <Router>
    <Suspense fallback={<div>Loading...</div>}>
    <Switch>
    <Route exact path='/' component={HomePage} />
    <Route path='/questions' component={QuestionPage} />
    </Switch>
    </Suspense>
    </Router>
    )
    }

Benefits of Code Splitting

  • Faster Initial Load: Users see content faster, leading to a better user experience.
  • Reduced Bandwidth Usage: Only necessary code is downloaded.
  • Improved Performance: Smaller bundles are faster to parse.

In Conclusion

Code splitting is a crucial technique for optimizing the performance of your React applications. By delivering only the necessary code to the user, you can significantly improve load times and create a smoother, more enjoyable experience. As you continue to build larger and more complex applications, code splitting will become an essential part of your development workflow.

In the next article, we will look into more techniques to boost the performance of our application.