With every release, browsers try to improve how they serve websites so they can provide a faster experience to their users. Speeding up their own code, optimizing JavaScript execution, and forward scanning for resources are only some of the techniques they use.
Sadly, that’s not always enough. Sometimes we, the authors, have to give user agents more information about what assets are going to be needed in the future. Resource Hints, including preconnect, preload, and a few others help us provide that information.
In this post, we’ll cover what Resource Hints are and their double-sided impact on your online store performance. We’ll also show you how to implement them using Liquid filters to achieve the best results possible.
What are Resource Hints? Jump to heading
Resource Hints including: dns-prefetch, preconnect, prefetch, and prerender are relationships of the HTML link element (<link>
).
These primitives enable the developer, and the server generating or delivering the resources, to assist the user agent in the decision process of which origins it should connect to, and which resources it should fetch and preprocess to improve page performance.
The two most common hints we see in Shopify themes are preconnects and preloads. While this article focuses on the latter, it's worth mentioning both, given their widespread usage.
Warming up connections with preconnect
Jump to heading
If you read our article about moving assets to Shopify’s CDN you should already know that the browser has to spend extra time to warm up the connection to each external domain. It’s not possible to serve every single file from your main domain so preconnects are often used to move this overhead earlier. This increases the chance that the files will start downloading immediately when discovered because the connection was already set up.
Liquid doesn’t provide any dedicated filter for preconnects. The way to define them would be to add an HTML <link>
in your theme’s <head>
section:
<link rel="preconnect" href="https://some-external-domain.com">
Keep in mind that while this is one of the cheapest hints you can do, its impact on performance is still not zero when done incorrectly. Before you apply it, there are cases where preconnect is not necessary:
- To cdn.shopify.com – it’s done automatically.
- When there are no actual files fetched from the given origin. Theme authors may include preconnects that may not be needed in your store’s final implementation.
- In conjunction with preloads to files from a given domain.
- To domains that are referenced in the <head> section of the page as they should be discovered early anyway.
- When files can be served from Shopify’s CDN instead.
That said, your mileage may vary and you should always test your changes by comparing before and after state using WebPageTest.
Preloading late-discovered assets Jump to heading
Compared to preconnects, preloading allows us to be even more explicit. Not only can we tell which domain is going to be needed, but also point to the exact file that should be downloaded.
In our screenshots, we have a situation where the font file is referenced in an external stylesheet. This means that the browser has to download the CSS first, before discovering other resources. By adding a preload, we are able to tell that the file should be treated as critical and fetched way earlier.
An LCP image set as a background in CSS or lazyloaded by JavaScript would be another popular example where it may be tempting to use this technique. However, make sure that you’re not trying to fix the symptoms of a real problem, which is not letting the preload scanner do its job. You would be better off fixing those issues first using the alternatives mentioned in Jeremy Wagner's article.
Liquid lets you define preloads in multiple ways including preload options for stylesheet_tag and image_tag. There's also a generic preload_tag filter. You should always use these over plain HTML as Shopify is going to send them even before the main document response, so this:
<link href="{{ 'script.js' | asset_url }}" rel="preload" as="script">
<link href="{{ 'style.css' | asset_url }}" rel="preload" as="style">
<link href="{{ 'image.png' | asset_url }}" rel="preload" as="image">
can become this:
{{ 'script.js' | asset_url | preload_tag: as: 'script' }}
{{ 'style.css' | asset_url | stylesheet_tag: preload: true }}
{{
product.featured_image
| image_url: width: 600
| image_tag: preload: true
}}
The only caveat is that Liquid filters limit the files only to the ones hosted on cdn.shopify.com. For any external asset you’ll still need to add the plain HTML to the <head>
section.
All the cases where you should avoid preconnects apply to preloads as well. Before you preload every single of your theme’s assets, a warning: when everything is important, nothing is. Browsers try to use the user’s bandwidth the best they can and incorrect preloading can be even more detrimental to your site performance then preconnecting or having no preloads at all.
Summary Jump to heading
Resource Hints allow us to influence the way browsers process our websites. Preconnect prepares a connection with an external domain, and preload triggers early download of a certain file for future use.
But with great power comes great responsibility. It’s not rare to see an incorrect use of Resource Hints. You should always test the influence of your changes on performance metrics. Fortunately, after reading this article you should have all the knowledge to implement them when needed, both in Liquid and plain HTML.