Jessica S. Reuter Castrogiovanni Writer. Scientist. Programmer. Accessibility advocate. I write in hopes to make the world a smarter and better place for my little techie-in-training.

Code splitting in React: An overview

4 min read 1133

Code Splitting React Overview

JavaScript, though written to be a simple language, can produce surprisingly complex code bases. Part of the reason is that there is a wide variety of classes and modules available. Most substantial JavaScript programs and frameworks have many dependencies, which can make a seemingly simple project accrue a large amount of code quickly.

The more code a project has, the slower the browser will load. Therefore, you often have to balance the size of your dependencies with the performance you expect out of your JavaScript. Code splitting is a useful way to strike this balance.

What is code splitting?

Many JavaScript frameworks bundle all dependencies into one large file. This makes it easy to add your JavaScript to an HTML page. The bundle requires only one link tag, and there are fewer calls needed to set up the page since all the JavaScript is in one place. In theory, bundling JavaScript in this way should speed up page loads and lower the amount of traffic that page needs to handle.

At a certain point, however, a bundle grows to a certain size at which the overhead of interpreting and executing the code slows the page load down instead of speeding it up. This tipping point is different for every page, and you should test your pages to figure out where this is. There isn’t a general guideline — it all relies on the dependencies being loaded.

The key to code splitting is figuring out which parts of a page need to use different JavaScript dependencies. Code splitting allows you to strategically omit certain dependencies from bundles, then insert them only where they are needed. This means they are also not loaded until they are needed — loading JavaScript only when it is needed speeds up the page’s load time.

This may seem counterintuitive at first since the page is still loading the same amount of code, but the difference happens because the page may not execute all the code it loads. For example, if a dynamic element in a page requires a large dependency, that dependency could cause a noticeable page lag. If the dependency is loaded only when the dynamic element is used, however, the dependency may be small enough where no lag is generated.

Code splitting is a common practice in large React applications, and the increase in speed it provides can determine whether a user continues using a web application or leaves. Many studies have shown that pages have less than three seconds to make an impression with users, so shaving off even fractions of a second could be significant. Therefore, aiming for three seconds or less of load time is ideal.

How does code splitting work in React?

There are several ways to implement code splitting in React. Different bundlers work in different ways, but React has multiple methods to customize bundling regardless of the bundler used.

Dynamic imports

Perhaps the simplest way to split code in React is with the dynamic “import” syntax. Some bundlers can parse dynamic import statements natively, while others require some configuration. The dynamic import syntax works for both static site generation and server-side rendering.

Dynamic imports use the then function to import only the code that is needed. Any call to the imported code must be inside that function.

We made a custom demo for .
No really. Click here to check it out.

import("./parseText").then(parseText => {
  console.log(parseText.count("This is a text string", "text"));
});

Using React.lazy

React.lazy allows for lazy loading of imports in many contexts. It is not yet available for server-side rendering, but its diversity of functions makes up for that. The React.lazy function allows you to dynamically import a dependency and render that dependency as a component in a single line of code. The component must be rendered inside another component that shows fallback content if the dynamic import fails.

This can include error content, although this is not required. If error content is included, it must be included in a special type of component called an Error Boundary. The Error Boundary component must be above any components that are dynamically loaded to make sure they display properly.

import React, { Suspense } from 'react';

const comp1 = React.lazy(() => import('./comp1'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <comp1 />
      </Suspense>
    </div>
  );
}

Choosing split points

The goal of code splitting in React is to give users the best dynamic experience possible. This makes choosing the places within code to dynamically load dependencies an important task.

React provides a good default place to start in its routes since users expect a slight delay when switching between pages. Dynamic code splitting on routes usually involves some dependencies of its own, but since users often expect some form of page transition, a little purposeful delay during loading might be useful.

How does code splitting work with component chunks?

React also allows you to split your code based on components, rather than on raw functionality. Sometimes a developer will have a group of React components that create a key piece of their page, and they will use that same group of components multiple times. When this happens, lazy loading the components’ dependencies every time the components are needed could slow down the page.

The React-loadable function gives you the ability to create a customized loader that dynamically imports the chunk of code required only once. Wrapping the dynamic imports in a loader prevents them from being included in a page load bundle.

import Loadable from 'react-loadable';

function ProgressDiv() {
  return <div>Div Loading In Progress...</div>;
}

const LoaderContainerComponent = Loadable({
  loader: () => import('./loadable-another-component'),
  LoadingComponent: ProgressDiv
});

class MyComponent extends React.Component {
  render() {
    return <LoaderContainerComponent/>;
  }
}

The same process can be used whether loading one or even a group of components many times. Loading a group of components often requires multiple dynamic imports and extracting the component types needed, but the basic idea is the same.

Even after chunking is optimized, it can be difficult to keep track of a chunk’s contents. By default, chunks have randomly generated names that can make debugging difficult.

Some bundlers, like Webpack, let you name your chunks by putting comments into your component loader implementations. Naming chunks can help you figure out how much overhead is required to load each one. Loading too many small chunks could slow down a page more than having a single large chunk, even if everything in the large chunk isn’t used every time the page loads.

React eliminates a lot of manual work from the code splitting process, allowing developers to focus on creating robust programs. Code splitting is an essential part of the modern web, so it’s no wonder that so many developers depend on it within React.

 

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Jessica S. Reuter Castrogiovanni Writer. Scientist. Programmer. Accessibility advocate. I write in hopes to make the world a smarter and better place for my little techie-in-training.

Leave a Reply