DEV Community

Alireza Jahandideh
Alireza Jahandideh

Posted on

Shopify theme and Webpack code-splitting

In this post, I want to share how to leverage code splitting for your Shopify theme. There is a minor issue to implement it as you would typically do in a Webpack project which I will share a solution for it.

What is code-splitting, and why you may want to do it?

If you don't know what code-splitting is, then, in short, it is a way to deliver the least amount of JS to the browser on page load and let the loaded JS decide when to download the other parts of the code. It makes your website faster to load fists, but the user pays the cost of downloads later in the journey.

How is it done with Webpack?

Basically, all bundling tools are capable of code splitting. You can see a report about it here: https://bundlers.tooling.report/code-splitting/

With Webpack there are multiple ways to achieve code-splitting, for the sake of an example you may split lodash like so:

import('lodash').then(({ default: _ }) => {...})
Enter fullscreen mode Exit fullscreen mode

To read more, start here: https://webpack.js.org/guides/code-splitting/#dynamic-imports

After building, you will get two bundled JS files:

  • index.bundle.js
  • vendors-node_modules_lodash_lodash_js.bundle.js

You only include index.bundle.js into your Shopify theme. For example, in the head of /layouts/theme.liquid and then the inde.bundle.js will load the other bundles (if needed) afterwards.

<script src="{{ 'index.bundle.js' | asset_url }}" defer></script>
Enter fullscreen mode Exit fullscreen mode

The problem

The problem is Shopify serves your theme assets from a CDN that has a different domain. Also, the URL structure is not what Webpack would figure out by itself. Assuming your shop URL is myshop.com, you may see your index.bundle.js is loading from https://cdn.shopify.com/s/files/1/1844/8937/t/273/assets/index.bundle.js

A Solution

Webpack provides an option to define the publicPath on the fly. We can specify the path in the first line of our JS src like this:

// keep this before your imports
__webpack_public_path__ = window.assetsPath;
Enter fullscreen mode Exit fullscreen mode

And the value of the assetsPath can be assigned in your /layouts/theme.liquid file.

<script type="application/javascript">
  window.assetsPath = "{{ 'index.bundle.js' | asset_url }}".split("index.bundle.js")[0]
</script>
<script src="{{ 'index.bundle.js' | asset_url }}" defer>
Enter fullscreen mode Exit fullscreen mode

And there you have it, code-splitting in your Shopify theme to improve your speed scores and make your client happier.

Cheers!

Top comments (2)

Collapse
 
sandymoresoda profile image
Sandy

Did you find a way for this to work in the dev theme editor?

Collapse
 
jeffoverhaul profile image
jeff-overhaul • Edited

I got it to work if you dynamically set the assets path using the global shopify object to detect if you are in the theme editor:

/* eslint-disable */
__webpack_public_path__ = process.env.NODE_ENV === 'production' || Shopify.designMode ? window.assetsPath : '/assets/'

Then you might need to add a different chunk filename output setting in your webpack config so that the shopify CLI detects changes to any modules:

output: {
...
filename: '[name].js',
chunkFilename: '[chunkhash].js',
},