Tiny tweaks for Shopify theme performance

I’ve been doing some research of late into pushing the limits of building extremely performant Shopify themes. Some of the stuff I’ve been looking in to is a little involved, involving wholesale changes to the way a site is built, and I haven’t quite had the time to write it up.

However, I thought I’d share a couple of very minor tips which are a breeze to implement with an existing theme, and are nice to have on a theme performance checklist (they’re now on mine).

1. Ensure you’re using HTTPS directly for assets

By default, Shopify’s asset_url Liquid filter outputs a protocol-independent URLs, turning this:

<script src="{{ 'js-respond-min.js' | asset_url }}"></script>

into this:

<script src="//cdn.shopify.com/s/files/1/0208/4064/t/6/assets/js-respond-min.js?9361327531464812605"></script>

The protocol-independent URL (the // prefix without a http: or https:) used to be a nice way of letting pages served over HTTP load assets via HTTP and pages served over HTTPS load assets over HTTPS. The latter avoiding the classic “mixed content” warning when a secure page loaded insecure assets.

However, these days the general recommendation is to attempt to serve “HTTPS everywhere”, meaning that if an SSL version of an asset is available it should be used.

Shopify’s taken this on board - if you try to load the HTTP version of an asset, their CDN servers will actually automatically redirect you to the secure version. That’s fine, but there’s a minor performance gotcha here as the majority of Shopify sites are hosted over HTTP, and hence any attempt to load assets using the asset_url filter will result in one request to the HTTP version of the asset, followed by a second request after we’ve been redirected.

We can avoid these extra request by simply ensuring we request the HTTPS version of the asset directly. We could use:

<script src="https:{{ 'js-respond-min.js' | asset_url }}"></script>

in our template files, but I actually like to go the extra mile and write it like this:

<script src="https:{{ 'js-respond-min.js' | asset_url | remove: 'http:' | remove: 'https:' }}"></script>

That way, even in the unlikely case that Shopify alters its asset_url filter to add the https: prefix by default, my theme won’t break.

2. Use the cross domain attribute for assets

If you’ve spent any time playing around with Google’s PageSpeed tool, you’ve probably seen this recommendation:

Serve static content from a cookieless domain.

Basically, sending cookies in a request when you’re not going to use them is a waste of bandwidth. It may seem trivial, but with a large enough cookie payload, a browser’s request can exceed the size of a single TCP packet and have a non-trivial impact on the request and response time.

Because Shopify sets cookies for *.shopify.com, currently all requests sent to the Shopify CDN (hosted at cdn.shopify.com) will contain those cookies. (I just checked and a default cookie payload for a Shopify site seems to run to ~1600 bytes).

While we don’t have any control over the way Shopify sets cookies for use, we can make use of a relatively new HTML attribute, crossorigin, to tell newer browsers to avoid sending them. Adding this attribute to image, stylesheet and script tags can be done like this:

<!-- The crossorigin attribute can be used on stylesheets, script tags and image tags. -->
<link href="https:{{ 'styles.css' | asset_url | remove: 'https:' | remove: 'http:' }}" rel="stylesheet" crossorigin="anonymous">

<script type="text/javascript" src="https:{{ 'app.js' | asset_url | remove: 'https:' | remove: 'http:' }}" crossorigin="anonymous"></script>

<img src="https:{{ 'logo.png' | asset_url | remove: 'https:' | remove: 'http:' }}" crossorigin="anonymous" />

A minor improvement, but an improvement nonetheless!

Do you have any little performance tips like this you’d like to share? Let me know!