Shopify Functions with JS: A Guide to Extending Your Store's Checkout using JavaScript

2023-03-14

Overview

This article provides an overview of Shopify Scripts and Shopify Functions.

We will explain how Shopify Scripts enabled merchants to customize their checkout experience for the first time and how Shopify Functions are set to replace them.

Finally, we introduce Javy, a build tool and runtime engine that allows developers to use JavaScript in WebAssembly.

Background

In February, Shopify made a major announcement about the deprecation of the checkout.liquid file1 and Shopify scripts2.

By August 13, 2024, both will become obsolete in favor of using new checkout extensibility options such as Shopify Functions.

This is a big deal for many Shopify brands, as they now have until the deadline to move any custom checkout logic or customizations to the new extensibility methods.

In this blog post, I'm focusing on Shopify Functions, but I plan to discuss the other extensibility features in future posts.

What are Shopify Scripts and Shopify Functions?

Shopify Scripts, released in 2016, gave Shopify merchants the ability to customize their store checkout experience for the first time.

For example, using a Shopify Script you can hide a specific payment option in the Shopify checkout by creating and editing a Ruby script. This all can be done directly from the 'Script Editor' app in the Shopify Admin.

To do so, you can use a basic script template provided by Shopify for this purpose. An example of this script looks like this:

Output.payment_gateways = Input.payment_gateways.delete_if do |payment_gateway|
  payment_gateway.name == "Shopify Payments"
end

Shopify Functions

In March 2023, Shopify Functions were announced and made available in developer preview, aiming to take over and improve where Shopify Scripts left off.

Shopify Scripts and Shopify Functions are two quite distinct ways to enhance and customize Shopify's checkout.

Shopify Scripts are written in Ruby and can be created and published from the Shopify Admin.

Shopify Functions, on the other hand, can be written in any language that compiles to WebAssembly (Wasm) and deployed through a Shopify app.

One of the most obvious challenges of using Shopify Functions is the need to write code in a language that compiles to WebAssembly.

Despite this hurdle there are plenty of benefits that come along with it.

Shopify Functions ultimately simplifies the process of customizing checkouts for merchants as they no longer need to write any code, and can simply install a Shopify app for the checkout customization they need.

Shopify Functions allow developers to extend or replace key parts of Shopify’s backend logic with custom code, which in turn allows merchants to create powerful ways to promote their products.

In addition, Shopify Plus merchants have the exclusive ability to write their own Shopify Functions and use them on their stores by using custom apps.

Right now you can only use Shopify Functions for discounts, shipping, and payment methods. But, support for shipping rates, checkout and cart validations, return validations, and order routing are planned to be added in the near future.

Options for JS developers

Common languages for compiling to WebAssembly are C/C++, Rust, and AssemblyScript.

These are not typically languages Shopify Developers are familiar with.

On one hand, Shopify Functions offer a great way to learn a new language. On the other, it would be beneficial to have a solution for developers using JavaScript.

Enter Javy.

Actually before I continue I should mention that in researching this topic, I found there are a couple other options for JavaScript developers to compile their code to Wasm. See duktape or spidermonkey-wasm-rs if you are interested in seeing some of these other options.

However, I'm writing about Javy because it is supported by Shopify will be used in the SHopify CLI and it will be used as the preferred method for creating Shopify Functions in the future.

Rust of course is always an option, but it will take some time for developers to become proficient with it.

If you want to start to writing Shopify Functions today and are comfortable using JavaScript, then Javy is the tool for you. JavaScript support in Shopify Functions is still in developer preview, but we anticipate it becoming available to the general public in the coming year.

What is Javy?

Javy is a JavaScript-to-WebAssembly toolchain that enables developers to use JavaScript in Wasm.

Saul Cabrera at Shopify created a general-purpose tool for anyone who wants to work with JavaScript in Wasm.

I appreciate that Shopify is striving to create a tool that anyone can use in any situation.

While we’re motivated by the Shopify Functions use case, we aim to keep Javy general purpose and have no Shopify-specific code shipped in Javy.

Javy is a build tool and runtime engine in one and is used by the Shopify CLI to compile your JavaScript code to Wasm.

It takes a JavaScript file and compiles it into a WASI-compatible WebAssembly module, which contains both the code and a full JavaScript engine embedded.

For a more in-depth exploration of how Javy was created, I suggest reading the article at Bringing Javascript to WebAssembly for Shopify Functions. It will provide you with a comprehensive understanding of the development process behind the making of Javy.

JavaScript Shopify Function

I won't go into detail about how to write a full Shopify Function in JavaScript, but I'll give you a quick example of the new JavaScript code by translating the Ruby script from above to hide a payment option in JavaScript:

// @ts-check

// Use JSDoc annotations for type safety
/**
 * @typedef {import("../generated/api").InputQuery} InputQuery
 * @typedef {import("../generated/api").FunctionResult} FunctionResult
 * @typedef {import("../generated/api").HideOperation} HideOperation
 */

/**
 * @type {FunctionResult}
 */
const NO_CHANGES = {
  operations: [],
}

// The @shopify/shopify_function package will use the default export as your function entrypoint
export default /**
 * @param {InputQuery} input
 * @returns {FunctionResult}
 */
(input) => {
  // Find the payment method to hide
  const hidePaymentMethod = input.paymentMethods.find((method) =>
    method.name.includes('Shopify Payments')
  )

  if (!hidePaymentMethod) {
    return NO_CHANGES
  }

  // The @shopify/shopify_function package applies JSON.stringify() to your function result
  // and writes it to STDOUT
  return {
    operations: [
      {
        hide: {
          paymentMethodId: hidePaymentMethod.id,
        },
      },
    ],
  }
}

This is quite obviously more verbose than the Ruby code mentioned before, however, it isn't that much more to write and there are obvious performance gains.

And I just want to mention it again here, but from a merchant's perspective, they do not need to write any code to add this functionality to their store. They can simply install the Shopify app with this function on their store and then customize it from the app's settings screen.

Conclusion

In conclusion, Shopify Scripts and Shopify Functions are two distinct ways to customize a Shopify store.

While Shopify Scripts are written in Ruby and can be created and published from the Shopify Admin, Shopify Functions are written in any language that compiles to WebAssembly and deployed through a Shopify app.

For JavaScript developers, Javy is a great asset to compile code to WebAssembly.

If you have some time you should definitely give it a try!

Footnotes

  1. https://changelog.shopify.com/posts/the-checkout-liquid-theme-file-is-being-deprecated

  2. https://changelog.shopify.com/posts/shopify-scripts-deprecation