Code splitting with Webpack dynamic import in React

This post is a practical approach to the concept of code splitting in frontend apps with React. We will learn why the code splitting concept exists, its advantages and how you can employ the concept in your React apps. We will also compare scenarios where splitting was employed and where it wasn’t so as to get a clearer understanding of why code splitting is so important.

In case you are still wondering on why you should care about this, then load speed is one concern to consider. To give the user a feeling of a more responsive network request, you need to start by reducing the size of data they have to download as much as possible. 51% of mobile internet users say that they’ve encountered a website that crashed, froze, or received an error.

What gets in the way of learning code splitting most times is the confusion that two features in webpack are trying to contradict each other. They are asset bundling and code splitting. Before we dive into splitting, let’s get this confusion out of your way.

What you need to know

The only knowledge required to get on with this article is fundamentals of:

  • JavaScript
  • React
  • webpack

Asset bundling

This is actually why tools like webpack and browserify existed in the first place. The first thing that comes to your mind when you hear their names is “asset bundling”. Bundling is the act of merging your browser assets into one file so that the amount of HTTP requests and calls to the server are reduced.

For example, I could have a math.js file and an index.js file just for structure. The math.jsfile defines a method that computes values while the index.js is where the method is called:

math.js

    export const add = (a, b) => a + b
    export const subtract = (a, b) => a - b

index.js

    import { add, subtract } './math.js'
    const a = 5;
    const b = 3;
    console.log(add(a,b))
    console.log(subtract(a,b))

When we run index.js through a bundler like webpack, it recursively resolves all of the dependencies and merges them into a single file that could be called bundle.js:

    const add = (a, b) => a + b
    const subtract = (a, b) => a - b
    const a = 5;
    const b = 3;
    console.log(add(a,b))
    console.log(subtract(a,b))

Just like I mentioned, this approach helped reduce the trips we make to a server, hence an attempt to optimize the experience.

Code splitting

Code splitting is a feature that helps you add split points in your code based on the user journey. These split points are then downloaded when the user embarks on the related journey or is about to.

For example, your split points can be routes where you download each route code when the user visits or wants to visit a route. The split point can also be a component or function that does a heavy computation. You can render other parts of a page and then asynchronously load the heavy component while providing a good pending user experience.

Since HTTP v2 is becoming more popular, code splitting now has more opportunity to shine better as HTTP v2 favors multiple smaller asset downloads to a bundled heavy download.

Let’s see an example that makes use of routes as split points. We will build the app without splitting and measure, then we’ll add code splitting, measure it again and let the metrics judge which is better.

Create a React app

Start with creating a React app using the create-react-app CLI tool:

    ## Install the CLI tool if you don't already have it
    npm install -g create-react-app
    ## Create a new React project
    create-react-app react-router-code-splitting

Install the following dependencies to the new React app:

    ## cd into the folder
    cd react-router-code-splitting
    ## Install dependencies
    npm install --save react-router-dom react-loadable react-spinkit

We will go into the details of what each dependency is but here is a short note on them:

  1. react-router-dom is the React Router for the browser or DOM environment. We will use this to set up routing in the app.
  2. react-loadable is a library that makes code splitting in React easy to work.
  3. react-spinkit is a loading component library for React

Update src/index.js to set up the router:

    //...
    import { BrowserRouter as Router } from 'react-router-dom';
    ReactDOM.render(
      <Router>
        <App />
      </Router>,
      document.getElementById('root')
    );

Create two components to serve as the pages for our routes named home and about:

src/Home.js

    import React from 'react';
    const Home = () => (
      <div>
        <h2>Home page</h2>
        <p>....</p>
      </div>
    )
    export default Home;

src/About.js

    import React from 'react';
    const About = () => (
      <div>
        <h2>About page</h2>
        <p>....</p>
      </div>
    )
    export default About;

Next import these components in src/App.js so as to use them for the routes:

    import { Route, Switch, Link } from 'react-router-dom';
    import Home from './Home';
    import About from './About';

We are also importing RouteSwitch, and Link from the router library. We will use this components to create routes and link to them. We will do this in the App.js render method:

    render() {
      return (
        <div className="App">
          <p>
            <Link to="/">Home</Link> |
            <Link to="/about">About</Link>
          </p>
          <Switch>
            <Route path="/" exact component={Home} />
            <Route path="/about" component={About} />
          </Switch>
        </div>
      );
    }

Splitting route code

If we introduce split points at the routes level, the browser will only download code needed by that route and not all the bundled code. We will use the react-loadable and react-spinkits libraries to achieve this.

Replace the Home and About import lines with the following:

    import Loadable from 'react-loadable';
    import Spinner from 'react-spinkit';
    const Loading = () => <Spinner name="double-bounce" />;
    const Home = Loadable({
      loader: () => import('./Home'),
      loading: Loading
    });
    const About = Loadable({
      loader: () => import('./About'),
      loading: Loading
    });

Loadable takes an object as an argument. The object must be passed a value for the loaderand loading properties. The loader is the component we want to load asynchronously.It is achieved using the  [dynamic](https://developers.google.com/web/updates/2017/11/dynamic-import)[](https://developers.google.com/web/updates/2017/11/dynamic-import)[import](https://developers.google.com/web/updates/2017/11/dynamic-import) method. loadingis the component that Loadable will show while waiting for the loader component to get ready. The common use case here is to show a loading UI which you can achieve with react-spinkit.

Add a Contact component in the src folder named Contact.js:

    import React from 'react';
    const Contact = () => (
      <div>
        <h2>Contact page</h2>
        <p>......</p>
        ...
      </div>
    )
    export default Contact;

Load the component in the App.js file:

    const Contact = Loadable({
      loader: () => import('./Contact'),
      loading: () => Loading
    });

Then add a route that renders the component as well as a link that points to it:

    <div className="App">
      <p>
        <Link to="/">Home</Link> |
        <Link to="/about">About</Link> |
        <Link to="/contact">Contact</Link>
      </p>
      <Switch>
        <Route path="/" exact component={Home} />
        <Route path="/about" component={About} />
        <Route path="/contact" component={Contact} />
      </Switch>
    </div>

Note that most times, the bundle file will be cached since it hardly changes. The only speed you would have to worry about is that of the smaller chunks that are representing each of the routes we created in this project.

Conclusion

Performance is the web trend these days and if you want to stay competitive with your web product, you need to make sure that the app is fast or at least your users perceive it as being fast. Code splitting is one way to boost your app’s performance among other things like PWA which you should check out.

You May Also Like
Read More

Froxt DevDay

It’s almost time! Froxt DevDay – The Meetup, a fresh take on our yearly virtual developer event, begins…
Read More

Introducing Froxt DCP

In 2021, we started an initiative called Froxt Work Management (FWM) Cloud First Releases for Ecosystem which enabled…