Insight | Mar 4, 2020
The Definitive Gatsby Performance Guide
By Grant Glidewell
How to get everything from your Gatsby site, because speed is not a guarantee, and fast is not the same as ludicrous speed.
I've heard so many times when a Gatsby site is launched, “wow, that’s fast”. And the feel of a Gatsby site is almost psychic. The page loads are instant and the interactivity feels responsive in a way that few other sites can compete with. This performance comes from the work that Gatsby does out of the box. Many of these mechanisms are detailed in an article by Dustin Schau, it’s a great deep dive.
In this article, we will touch on a few commonalities between the fastest performing sites we found in our research and discuss why this makes them fast. The top ten sites have an average lighthouse score of 91. The average score across the web is 63. Don't be tricked into thinking this is a linear relationship. The difference between a score in the 90s and 60s multiple seconds of load time and many more seconds parsing and executing code, translating to users who bail while waiting for things to load or become interactive. This is nothing to sneeze at and can take a lot of development work to get incremental improvements in performance. However, with Gatsby these gains can be had at a much lower cost.
Use the tools Gatsby gives you
I want to discuss for a moment the reasons one might choose to use Gatsby. One valid reason is the developer experience. If that was your motivation, great. But your clients (or non-developer interests) probably don't care too much about you having a good experience using the latest tooling.
The selling point for Gatsby is that it produces ‘blazing fast’ sites. I see this on a regular basis on Twitter, a new Gatsby site announced, “Wow, that’s fast”. Speaking specifically to developers reading this: it’s on you to use this tool properly, don't fuck it up! What you start within Gatsby is a very high level of performance. Using their tools and following their best practices will go a long way in maintaining great performance.
“"It’s on you to use this tool properly, don't fuck it up!"”
In our analysis of many gatsby sites, something shocking stood out to me. I would hover a link, and watch the network tab. Many times, nothing would happen. Or I would scroll to an image halfway down the page and wouldn’t see the cool svg placeholder or blur-up effect I would expect. These are signs that someone built a Gatsby site without using some of the most powerful tools they offer. One is link pre-fetching using reach-router, and the other is image lazy-loading and optimizing via gatsby-image.
Images
All high performing gatsby sites have performant images. This means not only using a tool such as gatsby-image, but also making good decisions on when and where to use images for their content. Using images in a modern website is a double-edged sword. They can provide an awesome and unique experience for your users. But used incorrectly, they can become a barrier for entry. One of the best examples is Gold Medal Flour. They have lots of images, but every single image is perfectly tailored to its place, the largest image transferred is 96k.
Contrast that against another great performing site for the agency Edenspeikermann with their largest image being 214k. The latter site still has amazing performance, but that full height set of images and animations make a ten-point swing in lighthouse performance scores. Weighing what you want your user’s experience to be is important. For Edenspiekermann, they clearly wanted to show off their design chops, while Gold Medal Flour has a product to showcase and does so with great efficiency and speed to boot! You could also contrast this with sites like The State of JavaScript 2019 or the React Documentation site who have no images at all.
These sites are all using Gatsby-Image.The query fragments provided by gatsby image have options for no base64 encoding. Using these queries in places where you don't need a blur-up effect, and really don't want to risk large base64 encoded image date (like in the case of a background image), use those queries. Another good option might be to use the background color option with gatsby-image. The configurability of gatsby-image is there to help you fine-tune it’s used to your specific needs. Being thoughtful about how you use this tool can result in some massive performance gains. Think of this as a file or rasp where you can really start to shape and smooth the contours of your project. Do I need every image to blur-up, or just some featured images? Have I specified reasonable sizes for gatsby-image to work with at different resolutions? These are questions that will help you eek out some much better performance from Gatsby and make all of your users gasp with excitement.
Link Pre-fetching
Simply using the Link tag from react-router will give you nice pre-loading when a user hovers on the link. Dustin Schau of the Gatsby team has a great article that covers this in depth. In short, you should use it if you're using Gatsby. A number of sites we reviewed did not and it’s noticeable. There is no setup, install or anything needed to leverage this free performance! Just use what is already there and your users will thank you. All of the sites that tested as fast use this feature for their navigation. It’s a no-brainer!
Design
All fast gatsby sites have a design that lends itself to performance. These sites keep their information to the point, they clearly understand why their users are visiting and built their experience around that. A site like Dovetailapp has quite a bit of scrolling, however, their use of lazy-loading reduces the impact of that page size. Lazy loading means that if an element is not shown on the screen, the browser does not download it. So as a user scrolls the browser downloads what is needed.
A site that stands out as being very to the point, but is not just documentation, is Cardiogram. You instantly know what this app is and what it does. The graphs and interactivity are components lots of sites want to implement, this is an example of a design that made performance a priority.
React Performance Matters Too!
Static rendered !== fast. With Gatsby, we are hydrating a React application so all the performance considerations that go along with a React app will apply.
Gatsby doesn't address the mistakes many developers make in the process of building things with React. They handle some of the hard parts already like route-based code splitting and having a separate bundle for your vendor code. I also hear they’re working on a way to warn users of potentially problematic code in development. These features make Gatsby a powerful tool. But this shouldnt be the only tool in your box, after all, not everything is a nail.
Conditional rendering is something that is super straightforward in React. But be aware that it comes at a cost if you implement it in specific ways. One thing I see a lot of developers do which hurts their site’s performance is completely un-mounting components that may not need it.
An example of this might be the Menu on the TAGv5 website. In that menu instead of mounting the component, then running the css animations that come along with it (there are frame rate goals here), we use some css to keep it hidden. This isnt always the best option. Using a render bailout (where a component renders `null`) in some scenarios might make more sense if you aren't doing any animations with it. This helps to avoid the performance cost of mounting and unmounting components. If, however your component may _never_ be seen by a user, you should probably lazy load it.
There are places on web pages that never see the light of day. Thus loading those parts of a web page is wasted transfer bytes and processing power. To deal with this you can lazy load that content.
There are some great options for lazy loading like React’s native React.lazy (unfortunately not ready for SSR applications like Gatsby), or react-lazyload, a popular package that handles a lot of the details for you. If you’re more adventurous you can take a shot at replicating what we did in TAGv5 on our homepage. All you need to do is ensure that when the page loads (this applies to when the static site is rendered by Gatsby at build time), your lazily loaded component isnt in view and therefore doesn’t impact the user’s experience. This reduces the initial size of the HTML that is statically rendered.
React applications can get really complex and difficult to reason about. Especially if you start running into performance issues. There are some tools React has available to do some measurements.This is a deep topic on its own and there are some great resources available to get you started. Brian Vaughn has put some really useful tooling together specifically for React in the react dev tools. He has even put out a deep dive video. Making sure you are using React efficiently is important. If your users feel like your site is slow in some way, using these tools will give you some clues on what needs to change to get things running smoothly.
Third-Party Code
They have streamlined analytics and third-party scripts running on their sites. These have a significant impact on performance and we don't see them used in excess on any of the top sites in the group. You'll notice visiting these pages there isn't a single chatbot that pops up in the corner to ask if you need help. These sites often do have analytics, however, they have settled on one or two providers. This is something that, when performance is a priority, is very important. There is nothing a developer can do to improve the performance of third party code. It's simply out of their control and thus, the more tracking, analytics, chatbots, whatever is added to the site has very direct and uncontrollable impacts on performance. As a developer my insights into the strategic needs of the business are limited, however, we plan to dive into this topic a bit with savvy from our own strategy team.
Dealing with bundles
One hard part of developing modern JS is sometimes more about the ecosystem than problems with day to day development. There are a lot of open source libraries available to make development easier and solve common problems. These, however, come with a cost. Bundle bloat! Addy Osmani has some excellent material in The Cost of JavaScript 2019 on what this means for users. He also goes into some detail on how the browser (chrome in this case) handles JavaScript and how that impacts UX. It’s worth digging into if you want to have a deeper understanding of how the browser deals with JavaScript.
In Gatsby you still have to watch your web project’s bundle size. The static rendered pages are hydrated as React apps after the initial load, so all the same rules apply. Using large npm packages will have the same impact on bundle size and in turn performance. Understanding where this bloat comes from is a great first step to trimming off the extra bundle size.
Gatsby has a plugin to help you figure out what ends up in your bundle and at what size. The plugin gatsby-plugin-webpack-analyzer outputs a json document with details of your bundles. It will also display your bundles in a web explorer interface. There are alternatives to this interface and one of which is webpack-visualizer. This view of what your actual bundle looks like will allow you to make informed decisions on where to trim.
In doing this for TAGv5 we found that a library we were using to ease our work with SVGs was causing some very large bundles. Refactoring all the components that used this library took some time, but the result was well worth it. A small example of how we handled this is in this PR where we converted from relying on the library which did some magic when you imported using `{ ReactComponent as SVGName }`. These small optimizations go a long way if you diligently review what is contained in your bundles.
Analyze your issues, not slow connections
Understanding where your performance issues come from is important. For the sake of this article, I’m going to assume you’re using Chrome to develop. Testing while you build isn't as important as getting things done (at least according to business interests), but might give you some insights into the impact of each feature as you implement it.
There are some really cool features in gatsby cloud that will give you performance metrics as you push to your live environment. Thats, just, dope! However, you can take the same level of control with your project locally.
First things first, whether it’s local or hosted, running lighthouse should always be done in an ‘incognito’ window with no other extensions running. This ensures any performance issues you run into are from the code you wrote and not something in an extension. Google has some great documentation on how to use Lighthouse, and Lighthouse itself gives very direct feedback on how to solve common problems related to performance. If you would prefer to run tests against your hosted site and don't want to run chrome, there are some websites that provide similar insights. Google provides lighthouse via pagespeed insights. And there is also WebPageTest which provides some options for testing that includes running lighthouse, and testing on real devices.
Testing locally will isolate your code from performance issues that come from hosting or user connection issues. However you should ensure that you consider your hosting and distribution method into overall performance as well. Netlify has a nice CDN built into their hosting system. Using a content distribution network will allow users in many areas around the planet to access your content close to where they are.
Drop us a line
Have a project in mind?
Contacting Third and Grove may cause awesomeness. Side effects include a website too good to ignore. Proceed at your own risk.