Overview:
As a web developer that likes to focus on performance and SEO, seeing green across the board on Google’s Lighthouse test brings great satisfaction! It also tends to be a moving target as more content, media, and features get added to a website. Or Google will update its performance scoring calculator and what it takes to achieve those high scores in the 90+ range. You might ask, “why is it so important to have high scores in Google Lighthouse”? The reason is that your scores can affect your search results for your website. The most important metrics you want to focus on are what Google calls Core Web Vitals. Currently, the Core Web Vitals are Largest Contentful Paint, First Input Delay, and Cumulative Layout Shift.
- “Largest Contentful Paint (LCP): measures loading performance. To provide a good user experience, LCP should occur within 2.5 seconds of when the page first starts loading.“
- “First Input Delay (FID): measures interactivity. To provide a good user experience, pages should have a FID of 100 milliseconds or less.”
- “Cumulative Layout Shift (CLS): measures visual stability. To provide a good user experience, pages should maintain a CLS of 0.1. or less.”
Recently, I re-tested my site and realized my performance score was down in the 70s. This article will cover some of the steps I took to get my score all the way up to the high 90s!
Eliminate render-blocking resources
If you notice Lighthouse giving you errors about eliminating render-blocking resources, this is an easy to win to improve your LH scores. There are two types of resources that Lighthouse will flag as render-blocking. One is a `<script>` tag that is in the `head` of the document, does not have a `defer` attribute, or does not have an `async` attribute. The 2nd is a stylesheet that does not have a `media` attribute that matches the user's device.
In order to eliminate or reduce render blocking scripts, identify Javascript that can be moved to an inline script tag in the HTML. Any Javascript that is needed for content above the fold to function, can be identified as critical. Any Javascript that is non-critical can be left in your bundles or 3rd party scripts and then add `async` or `defer` attributes to the script tag.
As of `gatsby@4.15.0`, there is now support for the Gatsby Script API and Component. This component offers a convenient way to set different loading strategies and a default loading strategy that gives users great performance right out of the box. One really cool feature of this `Script` component is the `off-main-thread` strategy. What this strategy does is load the script off the main thread and into a web work via Partytown. This is great for loading 3rd party marketing or tracking scripts.
Optimize Images
Most experienced developers and SEOs know that all your images on your site should have descriptive alt tags that accurately describe your image. But you can take it a step further and make sure you are using the appropriate size and most optimized file formats for an image. For example, I noticed in a recent Lighthouse audit that the logo image was not sized correctly on my site and I was getting dinged for it. It just so happened that this image was a perfect candidate to be converted into an SVG. SVGs are way more performant than pngs and I now have more dynamic control of the graphic. I was able to improve my score by 10 points just by making this optimization over to SVG.
In the context of Gatsby websites, you’ll want to use gatsb-plugin-image package to gain automatic image optimizations. This plugin improves the developer experience as well as the end-user experience by only immediately fetching images “above the fold”, providing placeholders during image fetch, and minimizing image file size to improve the fetch and load speed of the asset. Another pro tip is to use the WebP format or AVIF which is a newer image format that offers even better file size and compression than WebP. If you want to learn more about these file formats check out this article from Smashing Magazine where they go over it in detail.
Optimize Fonts
The next issue I tackled was optimizing the way I was loading fonts. For my site, I was fetching my fonts as an external resource from Google Font API. This can be expensive to fetch resources over the wire and cause unwanted effects such as flashes of unstyled text when your text is rendered before the font family actually loads. Fetching fonts from external resources can negatively impact your Lighthouse scores when it comes to Time to Interactive and Cumulative Layout Shift. So instead of importing fonts into my stylesheets using the import syntax such as @import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap'), I downloaded them and reference them internally now. Another bonus font optimization is to only use the Latin font subsets only. It's not uncommon that lazy developers will just include all the font extensions such as Greek, Cyrillic, etc. If you want to learn about other methods you can use to optimize your fonts check out this article, The Fastest Google Fonts by Harry over at csswizardry.com
Lazy Load components
Lazy loading my site's components probably gave me the biggest gain in this round of optimizations. Since my overall website is essentially a single page design, there is a lot of content, components, and javascript that gets loaded and executed on my home page. As a result, the site had to load large javascript bundle sizes and it was negatively impacting the Lighthouse scores. Any content you have below the fold can be deferred and loaded later when the user scrolls those components into view. The way I achieved this is by using `loadable-components`. `loadable-components` is the recommended solution for lazy-loading components SSR React components and also in Gatsby applications. By breaking up the site’s components into their own bundles and lazy loading, I was able to make significant gains in Lighthouse. You can find the Gatsby plugin here and read the documentation for using `loadable-components`.
Conclusion:
By spending a few hours auditing my website and implementing the optimizations covered in this article, I was able to bring my website from 75 to 97 in Lighthouse. Making sure your website stays fast and is taking advantage of all the modern optimization techniques is a moving target. By scheduling audits for your website on a monthly or quarterly schedule can help you stay on top of it. Or even take a step further and run Lighthouse reports as a part of your CI/CD build pipeline.