In this article, we want to show you specific ways to optimize for Google Lighthouse. This is going to be technical, so put on your developer hat and learn.
1. Making heavy things load only when needed
We start with investigating the bundle with the bundle analyzer:
As you can see, the main bundle is huge, including Adyen JS and other stuff. We need to refactor the code to avoid loading as much as possible, for React components:
You can use this trick to lazy-load heavy components, or create a code, that will only be reachable when React decides to render it. In this case, to avoid rendering heavy Adyen.css, we move it as a component and only call it when rendered, like so:
For functions, you can just use dynamic imports, like so:
This will help reduce the bundle size.
2. Removing libraries loaded from outside
Some scripts make pages heavier but are never displayed by a bundle analyzer because they might be loaded from a different place. But from where? In our example, it’s from index.php, but it could also come from custom GTM scripts, for example:
As you can see, this leads to the page loading jQuery on every page load. We want to avoid that as it adds 30+ kb on each request. But it looks like the react-owl-carousel requires it to work. What we can do is create a lazy component as before, and load the jQuery and the library itself only when the component mounts:
3. Making requests not repeat when made in the __construct function
There is a problem in the older version of @tilework/mosaic when you make a request in __construct. The request is made multiple times, once per child theme. We want to avoid that, and the fix is already merged into the @tilework/mosaic. All we need to do is upgrade it, like this:
4. Making CSS not blocking
Once all optimizations for a bundle are done, we can enable the optimizer extension. All it does is replace the default MiniCssExtractPlugin with css-loader, which injects styles directly into the head. This is important for pre-render as it allows for inlining of all CSS and disables source maps!
5. Making stuff not load for the crawler
There are many things considered useless for the crawler: GTM, analytics, recommendations, etc. We can avoid loading them by utilizing the isCrawler function, disabling the extension forcefully or preventing its execution:
There is a bug in the older Regex, which is global and leads to it keeping its state. It must not be global, so remove letter “g” from postfix /regex/gmi => /regex/mi, like so:
6. Avoiding font blinks
The fonts should always remain visible. Check all @font-face declarations and ensure they use font-display: swap. Add it everywhere it is missing (do not forget to check JS):
7. Making images lazy load automatically
The images should be lazy, but not all of them. Specifically, the ones that immediately appear in view (above the fold) should be loaded automatically (loading attribute set to eager), and the ones below the fold should have the attribute loading set to lazy. Let’s create such component:
Now, it’s time to integrate it. We should replace all the images of the app with it. To do it, we need to modify the Image component and add a new HTML rule:
8. Making requests use GET over POST
Lookup the network requests for POST graphql requests:
Making 6 uncached requests on every page load is crazy. It’s just too much! Lookup the code for fetchQuery and replace it with executeGet function, like so:
Make sure to avoid replacing potentially sensitive endpoints, like GeoIP with GET. Doing so can break the logic as it relies on user IP, which should be unique.
9. Removing repeated code from each style script
Each style should be unique. But sometimes, it is not. Notice the different style files having the same keyframes declaration inside:
Why did this happen? Because someone has included compiled styles into _abstract.scss. Let’s remove it and move to _root.scss instead.
10. Making links preserve their state
When navigating in a single-page app, we can pass the state along with the URL. We should utilize this feature. Take a look at the before and after (notice the full-page placeholders in the first case):
Case 1
Case 2
Here is how we can achieve this, by just passing a single prop to history push:
We can also adjust links if needed:
11. Loading images of the correct size
Notice the image size here:
If your site uses Fastly or Cloudflare, the image optimization option can easily be enabled. The parameters can then be passed to your image requests so that an image of the correct size is returned. Also, the new browser feature for images sizes/srcset allows for different image sizes to be selected:
12. Making additional information be a part of filter requests
Using product requests to pass additional information about the CMS blocks to be displayed on the PLP is not efficient.
It’s not efficient because the product request changes too often. To avoid it, you can move the retrieval of CMS blocks to filter requests, thus optimizing the product request even further:
You should ensure that the other queries are not affected (cart, wishlist, etc.) by adding some more logic to the product query to adapt to the cart/wishlist:
Then, set the correct product list flags before getting the query:
13. Making a full product request in the quick buy pop-up
Say we want full product information in the quick buy pop-up, which is shown on the PLP:
With our optimized PLP request, the same pop-up will display as empty (ignore the loader):
So, we need to load the full product on the pop-up click. To do that, let’s create a wrapper component over a product card so that we can replace the product data of the product card with new, full data on demand:
To fetch a product, just like on the PDP (and reuse cache!), we can use the following logic:
And there you have it! Go ahead and try these optimization tricks on your current or next project and watch your Lighthouse scores soar in no time.
If you’re looking for a partner to help you grow your eCommerce business, look no further. With our focus on innovation, expertise on web development, and eCommerce services, scandiweb is the perfect eCommerce agency for businesses of all sizes. Contact us today to learn more about our services and how we can help you achieve success in the eCommerce space. You can also send us an email at [email protected].
Share on: