Gatsby Code Splitting
Tags: gatsby, javascript, webdev, webpack
Published: 2021-07-05 20:22:45

Modern web apps are now thought of as *bundles of modules* interacting with each other to create functions/features. *Bundling* is the process of merging code into one "bundle" (think: script/file) to deliver to the user. 

__Code Splitting__ converts these 'bundles' from one file to many, which can further dramatically improve performance by __lazy-loading__ just the parts of your site that the user needs. 

#### Code Bundling Example (before code splitting):
Raw Code:
```javascript{1-4}
// /pages/Index.js
import { add } from '../components/math.js'

console.log(add(15, 15)); // 30
```
```javascript{1-4}
// /components/math.js
export function add(a, b) {
  return a + b;
}
```
Bundled Code:
```javascript{1-5}
function add(a, b) {
  return a + b;
}

console.log(add(15, 15)); // 30
```

As you can see, *bundling* is the process of merging your imported files/"modules" into one "bundle". While this is great, it can lead to long load times as your as your application grows in size with added pages and functions.


---


### __Code Splitting__
You can speed up your site by only loading what the user needs rather than delivering the entire application at once.
E.g., by only loading the components that are ON the page the user is viewing. 

One thing that makes Gatsby powerful is that it does this for you. Gatsby automatically and intelligently code-splits bundles when you run `gatsby build`. However, it does so in a specific manner. For example:

Imagine your website has two pages: a Landing Page and a Contact Page. Each page has 2 unique components; 4 in total:

-- __Landing Page__
 - Hero.js (Component)
 - Services.js (Component)

-- __Contact Page__
 - ContactInfo.js (Component)
 - ContactForm.js (Component)

In a traditional React app, a user who visits the Landing page will download a bundle containing *all* of the components -- Hero, Services, ContactInfo and ContactForm -- despite only needing the Hero and Services components to correctly display the landing page. 

Multiply this by say, 10 pages, and you've got an issue on your hands - you're serving a 10 MB payload for a 1 MB page.

This is how Gatsby approaches code-splitting: __on a page-by-page basis.__


This strength of Gatsby can also be a real downside when creating a __single-page site__. Since Gatsby splits bundles up by page, you'll end up delivering an unnecessarily massive payload to the client, slowing down your Largest Contentful Paint / initial load times.

So...the solution?

---


### __Code Splitting Components instead of Pages__
Code-splitting helps you lazy-load only what the user needs and reduce initial load times without modifying the quantity of code you've written.

The React team created React.lazy and Suspense for implementation of this but, unfortunately, neither are compatible with server side rendering/Gatsby. 

Instead, they recommend using a library called [Loadable Components](https://github.com/gregberge/loadable-components "Loadable Components Github").

### __Using Loadable-Components with Gatsby__
Code-splitting components with [Loadable-Components](https://loadable-components.com/docs/getting-started/ "loadable-components Getting Started Page") in Gatsby is simple. Start by installing dependencies
```bash{1-4}
npm install @loadable/component
# or use yarn
yarn add @loadable/component
```

Then, on any page you wish to lazy-load a component:

Change:
```javascript{1-11}
import Hero from '../components/Hero'
import Services from '../components/Services'

export default function LandingPage() {
  return (
    <div>
      <Hero />
      <Services />
    </div>
  )
}
```
To:
```javascript{1-13}
import loadable from '@loadable/component'

import Hero from '../components/Hero'
const Services = loadable(() => import('../components/Services'))

export default function LandingPage() {
  return (
    <div>
      <Hero />
      <Services />
    </div>
  )
}
```

And that's all! `Services.js` will now be loaded in its own bundle, separate from the one containing `Hero.js`. As you see in this example, one method of using loadable-components for a single page site is importing content *above the fold* normally, and lazy loading content below it.

__Bonus: Specifying a Fallback without Suspense__

When you lazy-load a component, you're deferring it on the initial page load. Therefore, there will be a short period of time where your content is not visible. You can display a placeholder during that period: 
```javascript{4-6}
import loadable from '@loadable/component'

import Hero from '../components/Hero'
const Services = loadable(() => import('../components/Services'), {
  fallback: <div>Loading...</div>,
})

export default function LandingPage() {
  return (
    <div>
      <Hero />
      <Services />
    </div>
  )
}
```
The word "Loading..." will now display until your component is rendered.

### Did you find this article helpful?  
If you did, would you take a second to share the article by clicking below? It helps our cause immensely!  

Make sure to also click the follow button to get notified when new posts go live 🔔