Version 2.x

Nacelle Storefront SDK 2.x

Links

Why upgrade to Storefront SDK version 2.x?

Storefront SDK version 2.x was designed to provide an easy upgrade path from Storefront SDK version 1.x while offering some compelling upgrades for merchants, developers, and end users. New and improved functionality includes:

  • An all-new plugin architecture that puts you in control of the features and footprint of the Storefront SDK
  • A revamped .query method that elevates the GraphQL querying experience
  • CDN-powered Storefront GraphQL response caching with Automatic Persisted Queries (APQ) is enabled by default for drastically faster repetitive requests
    • Boosts performance of frontend components that rely on client-side data fetching
    • Speeds up frontend build times by minimizing request times for data fetched for every route, such as header and footer data
  • A 60% decrease in package size removes barriers to frontend performance
  • A greatly improved TypeScript experience
    • Full compatibility with GraphQL Codegen for a typesafe querying experience with excellent in-editor feedback and autocomplete
    • Commerce queries methods (.content, .products, etc.) return a single type - no more type assertions!

What's new in Storefront SDK 2.x?

Storefront SDK 2.x focuses on providing a solid foundation for crafting GraphQL queries for Nacelle's Storefront GraphQL API. This gives developers a high level of control over the data that flows through their eCommerce projects.

Breaking Changes

  1. The REST-style data fetching methods, such as content, products, productCollections, and productCollectionEntries provided in Storefront SDK 1.x have been moved to the Commerce Queries Plugin. The contentCollections and contentCollectionEntries methods are fully deprecated and are not available in the Commerce Queries plugin.
  2. For the .query method, the SDK no longer throws on errors. Instead, it returns a result object of the more standard GraphQL response in the form of { data, error }. This allows developers better control of how to handle errors. A function for onDataError can no longer be provided to the SDK. Users of Storefront SDK 1.x's .query method will need to be aware of these changes. The additional methods provided by the Commerce Queries Plugin will continue to throw errors instead of returning them to maximize compatibility with Storefront SDK 1.x.
  3. The Storefront function used to create the SDK was removed. Instead, the Storefront SDK is initialized as a new instance of the StorefrontClient class, which can be wrapped with Storefront SDK plugins for additional functionality.
  4. If using a Node.js version below 18, you must provide the Storefront SDK with a custom fetch implementation via params.fetchClient.
  5. Nuxt 2 projects should transpile the Storefront SDK:
export default {
  // ...other config,
  build: {
    // ...other `build` config,
    transpile: [
      // ...other `transpile` config,
      ({ isLegacy }) => isLegacy && '@nacelle/storefront-sdk'
    ],
  },
};

Non-breaking changes

  1. A fetch client can be provided to the Storefront SDK on initialization. This option can be useful when using the SDK in environments where the fetch API is not globally available.
  2. The query method now supports a richer GraphQL querying experience with GraphQL Codegen. This includes the ability to provide the query method with a TypedDocumentNode query for fully typed GraphQL responses when using TypeScript. The revamped query method also allows developers to supply queries using the /* GraphQL */ "magic comment" or graphql-tag. For more information about using the Storefront SDK with GraphQL Codegen, see our GraphQL Codegen guide.
  3. Defaults to using persisted queries when fetching data. This allows taking advantage of Nacelle's APQ layer for better response times for repeated queries.
  4. Some config options (such as the Nacelle Space Token) have been removed, while a few new options have been added.

📘

For a complete list of changes, check out the Storefront SDK Changelog

New Plugin System

The core of the Storefront SDK version 2.x is focused on providing a first-class querying experience for Nacelle's GraphQL API. To support this, a plugin system was created so that users can opt into additional functionality to best support their needs, while still keeping the core first-class Nacelle querying support provided by the core SDK.

Commerce Queries Plugin

The Commerce Queries Plugin is designed to support Storefront SDK 1.x users transitioning to Storefront SDK 2.x and supports various use cases that might not need the full control and customization associated with custom GraphQL queries. The plugin extends the Storefront SDK 2.x to add the REST-style methods that exist in the Storefront SDK 1.x (minus the contentCollections and contentCollectionEntries methods).

📘

Storefront SDK 1.x users who want as much compatibility as possible when migrating to the Storefront SDK 2.x should use the Commerce Queries plugin.

After upgrading a Storefront SDK 1.x-powered project to use Storefront SDK 2.x, we strongly encourage developers to use the Strangler Pattern to incrementally replace Commerce Queries method calls with query method calls. This will allow you to remove bloat associated with data payloads that contain fields that are not needed by your project's UI or business logic.

Automatic Persisted Queries (APQ)

Automatic Persisted Queries (APQ) is a GraphQL caching technique. To learn more about APQ, please see our Storefront GraphQL API docs. APQ is enabled in Storefront SDK 2.x by default, which makes it easy to take advantage of APQ's performance benefits.

We recommend leaving APQ enabled. If you need to disable APQ to accommodate an advanced use case, refer to the "Disabling APQ in Storefront SDK 2.x" recipe.

Adding to a project

Install

Begin by installing the @latest version of the Storefront SDK in your Node.js project:

npm i @nacelle/storefront-sdk@latest

Get credentials from the Nacelle Dashboard

Retrieve the Storefront Endpoint from the Nacelle Dashboard:

A screenshot from the Nacelle Dashboard's Space Settings > API Details page. The Storefront API section contains a field for "Storefront Endpoint." This field has a copy button on the right side of the field. Clicking this button copies the value of the field.

The Storefront Endpoint can be copied with a press of a button.

Initialize the SDK

Import the SDK and initialize it with your Storefront Endpoint from the Nacelle Dashboard.

import { StorefrontClient } from '@nacelle/storefront-sdk';

const client = new StorefrontClient({
  storefrontEndpoint: '<your-nacelle-storefront-api-endpoint>',
});

In addition to the (required) storefrontEndpoint, the Storefront SDK accepts the following initialization parameters:

Optional initialization parameters

previewToken

Type: string

A Nacelle Storefront GraphQL preview token. When supplied, the Storefront SDK will enter preview mode globally. To learn more, check out the Preview Mode docs.

locale

Type: string

An IETF locale string, e.g. 'en-US'.

fetchClient

Type: fetch

A custom fetch implementation. By default, the Storefront SDK uses globalThis.fetch for network requests. You can supply a custom fetchClient to use instead of globalThis.fetch. This is required if using the Storefront SDK with Node.js versions less than 18, because Node.js versions below 18 did not implement globalThis.fetch. Examples of custom fetch implementations include cross-fetch and isomorphic-unfetch. If using Node.js 18 and above, we recommend not specifying a fetchClient, unless a custom fetch implementation is needed to satisfy advanced use cases.

exchanges

Type: Exchange[]

The Storefront SDK uses the urql GraphQL client under the hood. Urql is a flexible GraphQL client that can be customized via exchanges. The Storefront SDK exports an array of defaultExchanges; these are used by default unless custom exchanges are specified in the Storefront SDK's initialization params. The default exchanges are:

export const defaultExchanges = [
  retryExchange,
  persistedExchange,
  fetchExchange
];

🚧

The order of the exchanges in the exchanges array matters. Be sure that the retryExchange and persistedExchange come before the fetchExchange.

Here's an example of initializing the Storefront SDK parameters with custom exchanges:

import {
  StorefrontClient,
  retryExchange,
  persistedExchange,
  fetchExchange
} from '@nacelle/storefront-sdk';

const client = new StorefrontClient({
  storefrontEndpoint: '<my-storefront-endpoint>',
  exchanges: [
    retryExchange,
    persistedExchange,
    myCustomUrqlExchange,
    fetchExchange
  ]
});

Data Fetching

Crafting GraphQL queries

The query method submits GraphQL requests to the Nacelle Storefront GraphQL API. It accepts an object with the following properties:

  • query - (TypedDocumentNode | DocumentNode | string, Required) A GraphQL query.
  • variables - (Record<string, unknown> | string, Optional) Object or stringified object containing any GraphQL variables used in the query.

The query method returns an object with the following properties:

Custom Graphql query example

// Get product handles from the 'collection-1' collection
const query = /* GraphQL */ `
  query ProductHandles($filter: ProductCollectionFilterInput) {
    allProductCollections(filter: $filter) {
      edges {
        node {
          productConnection {
            edges {
              node {
                content {
                  handle
                }
              }
            }
          }
        }
      }
    }
  }
`;

const variables = {
  filter: {
    handles: 'collection-1'
  }
};

const { data, error } = await client.query({ query, variables });

Transforming the responses of SDK methods

The Storefront SDK offers an after method that lets you run arbitrary transformations or side-effects when other Storefront SDK methods are called. The after method is very flexible and can be a practical tool for accommodating edge cases.

The after method accepts three positional arguments, method, callback, and callbackId:

  • method - (string, Required) The target method that the provided callback should be applied to.
  • callback - (function, Required) The callback function that should run after the method. The callback function has the following characteristics:
    • It takes the return value of method as input.
    • It should return either the unaltered input or a transformed version of the input. Failure to return a value from the callback will result in the method returning undefined.
    • It can be either synchronous or asynchronous.
  • callbackId - (string, Optional) A custom identifier for the provided callback.
    • If a callbackId isn't specified, an ID will be assigned automatically.
    • A callback will be overwritten if a new callback is registered to the same method with the same callbackId.
    • To clear a previously registered callback, call the after method with the method of interest, a null value for callback, and the callbackId of the callback that you'd like to clear.

After examples

// NOTE: The examples below demonstrate using the `after` method
// with data-fetching methods added by the Commerce Queries plugin.

// Example 1: Capitalizing the `product.title` of all product data returned by the `products` method

const capitalizeTitle = (words) =>
  words
    .split(' ')
    .map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`)
    .join(' ');

client.after('products', (products) =>
  // return a transformed version of the `products` data
  products.map((product) => ({
    ...product,
    title: capitalizeTitle(product.title)
  }))
);

await client.products(); // returns `products` with capitalized `product.title`s

// Example 2: Performing asynchronous side effects when the `content` method is called

client.after('content', async (contentEntries) => {
  const contentIds = contentEntries.map((entry) => entry.nacelleEntryId);

  // Register an event with a third-party service
  await observabilityClient.addEvent({
    type: 'content data requested',
    data: contentIds
  });

  return contentEntries; // Because we aren't transforming the data, we can return the
  // original `contentEntries` fetched by the `content` method
});

await client.content({ type: 'teamBio' }); // reports an event with the `observabilityClient`

Preview mode

Preview mode can be activated in the SDK either globally or on-the-fly. To learn more, check out the Preview Mode docs.