Vue.js components in Shopify themes

There are certain things that do not change over time: all dev tutorials start with a “hello world” example, junior developers want senior salaries and the world of e-commerce stands on the shoulders of JQuery.

Some time ago my employer decided to start using Shopify as a new e-commerce platform for our existing and new e-shop projects. “OK for me”, I thought, probably, it’s a good chance to learn something new, practice React or Vue and add several fancy words to my CV. Bring it on! But, as you might have guessed, few moments later life gave me a good lesson not to take anything for granted.

As a good mannered developer I started to explore the new platform by reading documentation and breaking apart available free themes. Little by little I opened to myself the “wonderful” world of SaaS with its upsides and downsides. With that being said I leave you the choice to scroll down the page until code examples or to stay here with me and read some of my observations about Shopify as a platform for theme developers.

The first thing that got my attention was data management which was absolutely different to what I used to work with before. There is no direct access to all the data on your site so you can not create a full back up or roll back to a previous version in case of any trouble. Also you no longer have exclusive rights on site’s data. You must give your consent to share some part of it with third parties like app developers when you want to add non default functionality to your site. And you should do it quite often as the default configuration is limited to a bare minimum. That’s very reassuring right? Definitely not for me but a SaaS platform comes as a package and you either take it or leave it. I guess we should take it and move on to the bright side.

What does Shopify have to offer to a front-end developer? For me the most valuable asset is a front-end API. It gives us an opportunity to build nice, clean, dynamic interfaces and helps us to deliver exactly what customers want at the right place and at the right time. Shopify does have a large API ecosystem that reaches every single piece of data that you may need to create your site or application. API comes in two major groups: “admin API” for back-end changes and app development plus “storefront API” to use on the client side. These groups are represented in three flavours: AJAX, REST, GraphQL. At first glance everything looks very promising. Right? With these API at hand there is no visible constrains on what can be done on the front-end, thus we should observe a considerable number of Shopify sites based on popular js frameworks. But wait a minute. You’ve probably already guessed that this is not the case.

If you randomly pick any Shopify store, open developer console and type “JQuery” there is a good chance that you find this object defined.

Hence the site one way or another uses JQuery library under the hood. Don’t you find this odd? How could that happen that the Shopify community has made a choice in favor of an obsolete js library? You may not like the answer.

Why JQuery?

At the beginning of the 20th century Ford Motor Company made a car available for masses. Since then the car ceased to be a toy in hands of rich enthusiasts and became a tool, an instrument to do business and make money. Of cause those cars had a simple construction, were made of cheap materials and were not very reliable but that was a trade off to make them affordable and produce in large quantities. Also don’t forget that an average driver should be able to handle this beast without much problems as well as a mechanic should not struggle a lot while fixing it in the middle of a corn field.

Great minds think alike. Looks like Shopify has chosen a similar path. It offers fully functional ready to use e-shop to everybody. A shop owner may not have any special knowledge or expertise in IT, all he should do is tweak a few settings here and there and he is good to go. But what if something goes wrong or does not work right in the “car”? The shop owner pulls over, lifts the hood to check the engine, looks aimlessly for a couple of seconds, realizes that he has not a slightest idea how it works and then starts to squeeze and pull different tubes and wires at random hoping that it will help get the car fixed. A driver who does not know how to fix a car can do more harm rather than fix anything.

So Shopify stepped up with a couple of protective measures — a rigid template system based on a proprietary language called Liquid with a web editor to work with the code from an administration panel. By the way Liquid is very similar to Twig. You may be familiar with it if you worked with Drupal for example. So with these measures in place, if the shop owner needs to fix something, he may access the code via a web editor and modify it. This time if something goes wrong, just use built-in version control feature and roll back to a previous file version. Quite simple. Obviously this is not a very convenient way to work with the code all the time and more complex cases require a dev environment on a local machine but in most simple cases a web editor is more than enough. Thus we came to the first major reason to favour JQuery.

Excessive code exposure

This means that any employee with access to the admin panel is able to change the code on the live site without notifying anybody. Say a content manager may change a home page structure and no one will be aware of this until somebody opens that page and notices that something has been changed. I’m sure such feature was added with good intentions but do you know where best intentions lead us to? Right…

Code exposure has several implications on the js side: if you want to change the code in the web editor, it should not be compiled. Therefore many theme developers don’t consider using ES6 and webpack perks for theirs projects.

The second major reason to go for JQuery is:

Ambiguous / not clear documentation

If you ever decide to create a new theme from scratch, think twice because it’s going to cost you a lot of time and nerves. When I was reading theme documentation, I could not get rid off a feeling that it was there not to help me understand how everything works and how internal components are connected to each other, but to give me an impression of what I may find in the theme as a developer without any detailed explanation why it has been done so. It’s like if we agreed that a car should have four wheels to run and one engine to spin them but it’s not said where and how the wheels should be attached to the car. As long as the vehicle is able to move forward, everything is fine. For example, the entire JS coverage is limited to three or four JS section functions, plus there was some information about where we can find JS files in a theme directory and how to add JS code in sections and templates. In somebody’s opinion that should be quite enough to create your own theme. But that’s not the case, because you can’t build a house without a clear blueprint. That’s why sometimes it is more reasonable to find a theme which is very close to what you are looking for and then modify it. Most likely such theme will be based on JQuery.

The third major reason and at the same time the pillar-stone of the whole Shopify economy is:

Marketplace

Sooner or later a shop owner comes to the conclusion that basic configuration is not enough and that it would be nice to have more features like: AJAX shopping cart, user-friendly filters at the collection pages, enhanced analytics, sale management system, wishlist, social share buttons, Instagram integration etc. In that case all the roads lead to the marketplace where thousands of developers are glad to sell their solutions or expertise to help out our guy with his problem. Developers create extra functionality in the form of applications. Some of them may inject their own Liquid, js or css code into the theme files to make a new feature available for an end user. That gives us another constraint on js side: in order to use applications we should not generate entire DOM structure with js. Otherwise we lose our advantage over other shops as it’s more beneficial to pay a reasonable amount of money and have the feature right away than pay a higher price for a custom solution with unclear time of delivery.

Let’s sum up our observations and then pass to the next chapter where I explain the cases where Vue.js may be a better alternative to JQuery.

List of js constraints:

  • js code should not be compiled
  • the entire DOM structure should not be generated with js

These constraints are hard to digest for any mainstream js framework but if we push these boundaries to some limits, we can find edge cases where the above-mentioned constraints will be turned in our favour. To make a quick assessment of your particular situation consider the following questions:

  • do you maintain more than 3 shops?
  • can you afford a custom theme development?
  • is a site’s speed a priority for you?
  • do you have a js developer in your team?
  • is it ok for you that some applications may not be compatible with your theme?

If the answer is ‘yes’ to all questions — welcome on board! For those who did not qualify I hope the rest of the article will also be interesting. It may give you some thoughts about alternatives to JQuery.

Why Vue.js?

Before I answer this question, it would be better to ask another one. Why should we bother to replace JQuery with something else? Simple answer is: it became obsolete long time ago, but developers continue to use it by inertia as many popular JS libraries depend on it. At some point it should be stopped to prevent us from falling into a vicious cycle when there is no other choice but JQuery. Switching to native JS is not as difficult as it may seem. For most simple use-cases there is an equivalent function in “vanilla js” though the syntax may be a bit different. Don’t worry, you will get used to it in no time.

Every time we call JS API via JQuery we pass by an extra layer of code and that impacts site’s performance because of CPU overhead and memory usage.

It’s probably not a big deal for desktop users, but think about mobile users who do not have either fast CPU or stable broadband connection, nor unlimited power supply.

Imagine that we have already reduced CPU usage and made our js code base a bit lighter by switching to native JS. Can we improve this even more? Yes, we can :) We can reduce the size of the document that the browser downloads on each page request and we can generate device specific DOM structure on the fly. That means that mobile users will get a lightweight document optimized for their device.

All this is possible with the help of one of the popular front-end frameworks such as Angular, React or Vue. Let’s have a look at what happens when we open any page in our shop.

The first thing that catches attention is the proportion between the initial DOM content size and the total size of js files. In case of frameworks usage (on the left) the resulting js size is noticeably bigger than the JQuery version (on the right) but the initial DOM structure is rather small as it contains a bare minimum of elements which represent a page structure without any details. Those details are being added to DOM later by js framework. That also explains why js files on the left side are larger — they contain a portion of the DOM structure missing in the initial DOM version. In other words we store a part of the DOM structure in js files. Is it the right thing to do? Let’s look at what happens during second page load.

Well, that looks much more promising. Once we have our js in the cache we reduce traffic consumption to the minimum. From now on we can adapt the DOM structure to a particular device we’ve opened this site on. If one element on the page has a different DOM structure for desktop and mobile versions, there is no more need to load them both and hide one of them later as we did with JQuery approach. We just add the right version of the element and keep the DOM structure as slim as it may be.

It’s nice to have js files in the cache but what if we change something in the code? In that case we will have to reload the entire js bundle. Taking into account its size, this is not a pleasant perspective. A famous rule “divide and conquer” comes to the rescue.

In general any js code consists of two main components: your custom code marked as yellow and its dependencies marked as green. When we add a new functionality or fix a bug, we make changes in the custom code only. So it would be reasonable to divide our js bundle in two parts and load them independently. Thus if we change something in the code, we will reload only a portion that was affected by these changes, leaving all the dependencies untouched in the cache. Also this pattern reduces loading time during the first page load as Shopify supports HTTP/2 protocol and loads multiple files in parallel.

At this point we had a quick glance at a conceptual difference between modern js frameworks and a classic approach with JQuery or native js. It’s time to say why I have picked Vue.js among other alternatives.

I would like to have a small, compact and well supported library with a clear code structure and fast learning curve to make the transition from JQuery or native js to a new framework as painless as possible. It is also worth mentioning that I narrowed the list of candidates to three well-known frameworks which are supported by a large community of developers and would not disappear from the radars in the near future: Angular, React and Vue.

We can see from the table above that Angular is not an option due to its complexity and overwhelming size. React looks much better but not good enough. It is 30% heavier than Vue and uses JSX syntax for templates, which sets the bar of entry requirements for developers a bit higher. The winner is Vue. It’s compact, it has familiar HTML syntax for templates and it allows you to do pretty much the same things that you would do with Angular or React. Here are two Vue features that will be very useful for theme developers:

  • single file components
  • declarative rendering

The first feature will help us to create embedded apps inside liquid templates. The second feature will be of help if you want to run a quick test of some functionality or idea without setting up a new working environment. Just open codepen or jsfiddle, and you are good to go. No compilation is needed.

Let’s code!

I assume that Node.js and Yarn have already been installed on your machine. If not, it’s a good time to install them. Also you should be familiar with the Shopify theme structure. We will use Gulp to watch for changes in the source files then to compile them with the help of webpack and finally to deploy them to the Shopify server.

To make my task a bit easier I will take a free Shopify theme “Debut” and then step by step I will explain how to add Vue components into it. For those who don’t want to waste time on reading and prefer to play with the code right away I have prepared a link to my github repository with a ready to use project which you may clone and play with on your local environment. I tried to leave comments along the code to make it more clear and readable, but if you find that some areas are not clear or confusing, you may always get back to this article for some hints or guidance. For the rest of you who decided to stick to the narrative I advise to have a look at the project on github as well to have at hand a full file version with code snippets that I will use as examples later.

First of all I downloaded the Debut theme files from Shopify and put them to the project’s src folder:

../src/
assets
config
layout
locales
sections
snippets
templates

I keep all the config and script files in the root folder:

../
.gitignore
babel.config.js
config.yml
gulpfile.js
package.json
webpack.config.js

The Debut theme has a “testimonials” section with a list of random testimonials on the home page. I’ll replace a liquid version of that list with Vue.js version.

Let’s modify theme.liquid file and rename original js scripts to keep them aside. The link to theme.js file stays unchanged as we will generate a new theme.js file with webpack later.

Extend the global “theme” object by adding a new property that contains a list of all the Vue applications available on the current page.

Add initial div element as a mount point for our future Vue component. To initialize and run this component we will need two things: a unique identifier to find it among other components on the page and input data to render the list.

Two parameters, “app_type” and “section.id”, form an app key. “section.id” is generated by the platform so it’s unique for each section, whereas “app_type” value is defined manually. Thus we may have multiple Vue applications of different types in the same section. “Json” Liquid filter converts section’s settings and section’s block data into a json representation that we store in the global js object associated with the application.

The next step is to write a service class QuotesApp for our application type. It will handle app initialization and destruction plus it links scss file with styles being used in the app. Inside the init function we mount a single file component with main app logic to the div element created earlier in the quotes.liquid template.

The code of the “quotes.vue” component is simple and straightforward. It takes a blocks array and renders a list of quotes. That’s it.

The last touch is to handle cases where we use the Shopify design editor. Among a variety of customization options the editor allows to add or remove any dynamic section on the home page. That means that we should be able to initialize our components after insertion and remove all component references when we delete a section from the page. Whenever one of these actions takes place, the editor emits a js event. In my case I added two callback functions for “shopify:section:load” and “shopify:section:unload” events.

The only tricky and potentially dangerous part here is the code evaluation on the line 12. Unfortunately it’s a necessary evil, because when a new section is being added to the DOM tree, the inline javascript block is not executed, so I should do it manually via eval function.

At this point there is a bunch of js files which I should compile into a single theme.js file and then upload it to the server. Shopify provides a command line tool for working with theme files on a local environment called “theme-kit”. It watches for changes in theme files and uploads them to the server if something has been changed. In other words it keeps a remote theme synchronized with a local one. It works fine until you need to compile multiple source files into a js bundle. From the performance perspective it’s better to pre-compile all Vue.js components and send to the client a code already prepared for rendering. Also if we use ES6 syntax with features that are not yet supported by majority of browsers, we need to transpile the code into ES5 format.

I use Gulp as an orchestration tool that watches for changes, compiles changed files with help of webpack and finally uploads the result to the server using a “node-themekit”. To start working on the project just run “gulp watch” and that’s it. Gulp will take care of everything else.

You may find the source code for this pet project on the github at the following link. Don’t hesitate to play around with the code and write in the comments if you find a better way to add Vue.js into Shopify themes.

Takeaway from this article

  • Classic Shopify themes are not a friendly environment for JS frameworks
  • JQuery is still a default weapon of choice but can be easily replaced with native JS to improve performance
  • In large projects some data intensive elements like cart, product pages, collection filters can be implemented as Vue.js components

Curious developer at The Other Store

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store