Accueil > Blog > Code splitting in Gatsby

Code splitting in Gatsby

Gatsby
Webpack
Performance

This article will be especially interesting for large Gatsby projects: +1,000 pages.
Also if your project uses React18 or +, use this method instead : https://youtu.be/lypEGNEIRKE

Gatsby is a very powerful meta framework for developing very quick loading sites. Which is very important for SEO and for UX.

With the generation of static pages of Gatsby, the TTFB (time to first byte) and the FCP (first contentful paint) are lowered a lot compared to a CSR site (client side rendering) resulting for instance from a React pure development. And with the optimization of picture loading, with Gatsby Image, comes as well the optimisation of the LCP.

And all this is done almost automatically with Gatsby! Incredible ! Nothing's left? Not really 😅 It would have been too easy.

The more your project grows, the more likely you will load more JS bundles than needed in some pages of your site. If you perform a test using PageSpeed Insights (pagespeed.web.dev) you may get this advice / opportunity to optimize your page :

PageSpeed Insights Analyze

This optimization opportunity occurs when you load javascript code that is not used by the page on which you are performing the test.

There are two main causes:

  • bad code splitting
  • third party scripts: GTM, Facebook pixels, etc.

In this article, we will see how to fix the main cause of this problem, bad code splitting. The second cause will be discussed in a second article.

How does Gatsby split your code natively?

Initially, Gatsby organize your JS bundles into 3 categories:

  • application-level chunks (shared with all pages),
  • template-level chunks (shared with all pages of the same template),
  • page-level data imports

Let's take the example of a news site that creates articles for each news, some having videos.

Our site has several page templates:

  • Home page template
  • News page template (potentially with videos depending on the news)
  • News categories page template (which lists and organizes news depending on their category)

We will focus on the news pages, which are the most important on the site. The specificity of our news pages is that they potentially have videos.
Therefore we need a library allowing a good management of these videos. Let's take Video.js for example. This library is perfect, it allows us to play videos in many formats (MP4, Webm, HLS, DASH, etc.) and it implements an easy way to customize our video player.

The problem with this library is that it’s heavy, 573.6kb MINIFIED, and 159.1 kB MINIFIED + GZIPPED.

bundlephobia Video js

According to bundlephobia, it can take up to 3.18 seconds to load in slow 3G. This can seriously spoil the experience of our site, which aims to be efficient and quick to load (which is why we decided to develop it with Gatsby).

Now we will check the bundles of our articles without videos, to see if they have also the Video.js imported.

How to analyze the bundles of each pages in Gatsby ?

Thanks to the gatsby-plugin-perf-budgets and gatsby-plugin-webpack-bundle-analyse-v2 plugins which are installed using this command:

npm i gatsby-plugin-webpack-bundle-analyser-v2 -D
npm i gatsby-plugin-perf-budgets -D
Enter fullscreen mode Exit fullscreen mode

We can see that our video library (Video.js) is loaded in all article pages, even if they don't have videos.

Bundle analyze of a page article without video :

Bundle analyze before code splitting
And we import 457 kb of JS :
Bundles size import before code splitting

I simplified the rendering of the analysis to make it more readable (Yes I'm a photoshop master)

That’s where code splitting sets in : we basically split the import of our VideoPlayer component (which itself imports and uses our Video.js library).

How to do code splitting with Gatsby?

Once we have identified what code to split by analysing the different bundles of the pages, we are able to code split the components containing the packages that we want to import only on page with videos : in our example, the VideoPlayer component.

To do so with Gatsby, complementary packages are needed :

  • @loadable/babel-plugin
  • @loadable/component
  • @loadable/webpack-plugin
  • gatsby-plugin-loadable-components-ssr

And add the gatsby-plugin-loadable-components-ssr plugin that we just installed to our plugin list in the gatsby-config.js.

Then we just have to use @loadable/component to import our VideoPlayer component:

import loadable from "@loadable/component"
const VideoPlayer = loadable(
  () => import("~/components/VideoPlayer/VideoPlayer")
)
Enter fullscreen mode Exit fullscreen mode

And then make sure to conditionally use the VideoPlayer component only if the article has a video:

{
  article.video && (
    <VideoPlayer
        src={article.video.url}
    title={article.video.intro}
    />
  )
}
Enter fullscreen mode Exit fullscreen mode

And so, now our pages without videos no longer have the Video.js library in their bundles:

(Always the same photoshop talents)
Bundle analyze after code splitting
Now we import 355kb of JS files, and we economize 2 requests!
Bundles size import after code splitting

Voilà, you have just seen how to create code splitting with Gatbsy.

But you should know that with React 18 and React.lazy(), it's now possible to create splitting code natively! Without the gatsby-plugin-loadable-components-ssr plugin ! So moving to React 18 seems then to be a good alternative.

I put here a list of some reliable sources to deepen what we have just seen together if you are interested: