Vue Storefront is now Alokai! Learn More
Migrating from 1.12.0 to SDK

Migrating from 1.12.0 to SDK

If your project uses @vsf-enterprise/commercetools@1.12.0, there are two possible update paths, namely, upgrading your project to use our SDK (recommended) or you may also stay with composables. Upgrading to the SDK will allow you to use the latest features Vue Storefront has to offer.

Update path 1: Rewrite your repository to use VSF Commercetools SDK instead of composables

This is the recommended update path, as it moves your project to use the latest generation of VSF software - the SDK. All new version releases are built with the SDK in mind, while composables are considered legacy.

When switching to the SDK, it is expected that the user's storefront will stop using the composables and getters from the @vsf-enterprise/commercetools package. Instead, the VSF framework-agnostic SDK should be used.

Before the migration, while still using composables, your Vue code for a product page may look like this:

<!-- MyProductPage.vue -->
<template>
 ...
</template>
<script>
import { defineComponent, computed } from '@nuxtjs/composition-api';
import { useProduct, productGetters } from '@vsf-enterprise/commercetools';
export default defineComponent({
  name: 'ProductPage',
  setup() {
    const route = useRoute();
    const { products, search, error, loading } = useProduct('products');

    const product = computed(() => productGetters.getFiltered(products.value, { skus: [route.value.query.productId] })[0]);
    // Other possible used getters:
    // const options = computed(() => productGetters.getAttributes(products.value, ['color', 'size']));
    // const configuration = computed(() => productGetters.getAttributes(product.value, ['color', 'size']));
    // const categories = computed(() => productGetters.getCategorySlugs(product.value));
    // const breadcrumbs = computed(() => productGetters.getBreadcrumbs(product.value)
    //   .map(breadcrumb => ({ ...breadcrumb, link: localePath(breadcrumb.link) })));
    
    return {
      products,
      search,
      error,
      loading,
      product,
    }
  }
})
</script>

And after the migration - already using the new VSF Commercetools SDK, it may look like this:

<template>
  <div>
    <div>Product: {{ product && "Got a product!: " + product.id }}</div>
    <div>Loading: {{ loading && "loading" }}</div>
    <button @click="search(productId)">Search</button>
  </div>
</template>

<script>
import { sdk } from "../sdk.config.js"; // will be shown how to configure later
import { defineComponent, useRoute, computed, ref } from '@nuxtjs/composition-api'

export default defineComponent({
  name: 'ProductPage',
  setup() {
    const route = useRoute();
    const productId = route.value.query.productId;
    const products = ref([]);
    const product = computed(() => products.value?.products?.results?.[0])
    const loading = ref(false);
    const error = ref(null);
    const search = async (inputProductId) => {
      try {
        loading.value = true;
        error.value = null;
        const receivedProducts = await sdk.ct.getProduct({ skus: [inputProductId] });
        products.value = receivedProducts;
        loading.value = false;
      } catch (e) {
        loading.value = false;
        error.value = e; 
      }
    }

    return {
      product,
      productId,
      loading,
      error,
      search,
    };
  }
});
</script>

The useProduct composable in the first example provided dynamically updating loading, products and error Vue refs which changed their value based on what happened when calling useProduct's search method:

const { products, search, error, loading } = useProduct('products');

As you can see in the second, post-migration example that uses the SDK - VSF no longer handles this framework-specific Vue logic. The dynamic error, loading and data refs are implemented around it by hand by the programmers.

const receivedProducts = await sdk.ct.getProduct({ id: productId });

It only fetches products from the Vue Storefront middleware, which queries the Commercetools API. The arguments to the SDK methods are fully typed and allow for filtering, using custom queries etc., so there's no need to learn the raw Commercetools API yourself. Implementing framework-specific logic, such as the error and loading refs are now responsibilities of the programmer using the SDK when developing their storefront.

Removal of @vue-storefront/core and dependence on Nuxt plugins

When migrating to the SDK, you will also need to remove the @vue-storefront/core package. This means you will need to migrate from using methods useVSFContext and onSSR.

Here are some common use cases that you'll need to migrate from:

  • Case: Login guards that use $vsf.$ct.api.isLoggedIn(): Migration: Use sdk.ct.isLoggedIn()
  • Case: URLs that use addBasePath() from the @vue-storefront/core package Migration: Prepend the result of calling useRouter().options.base to the URLs
  • Case: useVSFContext().$ct.config.countries Migration: If your store is restricted to particular countries, set them in Merchant Center on the URL https://mc.[region].gcp.commercetools.com/[project name]/settings/project/stores/[store id], then use sdk.ct.getStores() to fetch those countries.
  • Case: onSSR Migration: Use useAsync and useFetch from @nuxtjs/composition-api

Getters are removed in the SDK

Getters that were used in the composable approach no longer exist in the SDK approach. After migrating to the SDK, simply access the property returned by the SDK method.

- const { products, search, error, loading } = useProduct('products');
- const product = computed(() => productGetters.getFiltered(products.value, { skus: [route.value.params.productId] })[0]);

+ const products = ref(null);
+ products.value = await sdk.ct.getProduct({ id: productId });
+ const product = computed(() => products.value.products.results?.[0])

Reducing repetitive logic

The code in the post-migration example is presented in its simplest form. Of course - if viable for your case - you could re-implement VueUse's useAsyncState in your code-base to abstract away the repetitive error and loading handling. See the example below. Please be aware that the word "re-implement" is used because useAsyncState relies on native Vue Composition API, while you may be using @nuxtjs/composition-api.

Migration steps

  1. Remove the following packages:
    yarn remove @vsf-enterprise/commercetools @vue-storefront/http-cache @vue-storefront/nuxt
    
  2. Remove the VSF Nuxt plugins from nuxt.config.js.
    The SDK no longer uses the Nuxt context to contact the middleware. The SDK queries the middleware directly, such as http://localhost:4000/ct/getProduct.
       buildModules: [
         '@nuxtjs/pwa',
    -    [
    -      '@vsf-enterprise/commercetools/nuxt',
    -       ...
    -    ],
    -    [
    -      '@vue-storefront/nuxt',
    -      ...
    -    ],
       ],
       modules: [
    -    [
    -      '@vue-storefront/http-cache/nuxt',
    -      ...
    -    ]
       ]
    
  3. Install the @vue-storefront/sdk, @vue-storefront/middleware, @vsf-enterprise/commercetools-sdk and @vsf-enterprise/commercetools-api packages
    yarn add @vue-storefront/sdk @vsf-enterprise/commercetools-sdk @vsf-enterprise/commercetools-api @vue-storefront/middleware
    

    {type='info'}

    @vsf-enterprise/commercetools-api since version 1.19.0 requires Node version => 16 && < 19


    If not already present in your package.json, install these missing Nuxt plugins explicitly:
    yarn add @nuxtjs/composition-api@0.29.3 @nuxt/typescript-build @nuxt/core @nuxtjs/style-resources
    

    @nuxtjs/composition-api version is explicit because it seems that the latest version (0.33.1) does not attach the return value of setup() to the Vue instance.
    In case you run into issues with node-gyp missing when installing, please run yarn global add node-gyp and try again.
  4. Upgrade the nuxt package to at least 2.16.2. Without it, you will get errors regarding hash generation when using Node 18.
yarn add nuxt@^2.16.2
  1. Update your transpilation configuration so that the newly added packages in point 3 build. This is because those packages use the new "nullish coalescing" operators in ECMAScript and your current build configuration may not support them.
// nuxt.config.js
...,
build: {
  babel: {
    plugins: [
      ['@babel/plugin-proposal-private-methods', { loose: true }],
+     '@babel/plugin-proposal-optional-chaining',
+     '@babel/plugin-proposal-nullish-coalescing-operator',
    ],
  },
+ transpile: ['@vsf-enterprise/commercetools-sdk', '@vue-storefront/sdk'],
}
...

Make sure to install those Babel plugins as well:

yarn add @babel/plugin-proposal-optional-chaining @babel/plugin-proposal-nullish-coalescing-operator

Alternatively, you can just use the @nuxt/babel-preset-app:

yarn add @nuxt/babel-preset-app

then:

// nuxt.config.js
...,
build: {
  babel: {
+   presets(env, [ preset, options ]) {
+     return [
+       [ "@nuxt/babel-preset-app", options ]
+     ]
    }
  },
+ transpile: ['@vsf-enterprise/commercetools-sdk', '@vue-storefront/sdk'],
}
  1. If your package.json file has the engines field, update it to reflect the currently supported Node versions:
      "engines": {
    -    "node": ">=14 <=16"
    +    "node": ">=16 <19"
      },
    
  2. In the repository root (or the src/ folder), create a sdk.config.ts (or .js) file and fill it with the contents shown below.
    import { ctModule } from '@vsf-enterprise/commercetools-sdk';
    import { initSDK, buildModule } from '@vue-storefront/sdk';
    
    const sdkConfig = {
      commerce: buildModule(ctModule, {
        apiUrl: 'http://localhost:8181/ct',
        ssrApiUrl: 'http://localhost:8181/ct'
      })
    };
    
    export const sdk = initSDK(sdkConfig);
    

    Make sure that the apiUrl and ssrApiUrl match the extension name that you used for the Commercetools integration in the integrations property in middleware.config.js:
    // middleware.config.js
    module.exports = {
      integrations: {
        ct: {
          location: '@vsf-enterprise/commercetools-api/server',
    

    If the key in the integrations object for you is for example commercetools instead of ct, the apiUrl and ssrApiUrl properties should end with /commercetools.

    Once the sdk.config.ts file is created, you can then import the SDK to use in place of composables and getters in your .vue components as previously shown in the introduction to this document:
    import { sdk } from "../sdk";
    ...
    const products = await sdk.ct.getProduct({ id: productId });
    ...
    
  3. Remove all imports that use from '@vsf-enterprise/commercetools' and @vue-storefront/core, because we deleted these packages in point 1.
    This means you will have to rewrite your code from the Vue composable-based approach to the framework-agnostic SDK based approach, as shown in the introduction at the top of this document.

Update path 2: Stay with composables and update to @vsf-enterprise/commercetools@2.x.x

Using this update path will allow you to use a newer version of the API client.

  • @vsf-enterprise/commercetools@1.12.0 - uses @vsf-enterprise/commercetools-api@1.12.0
  • @vsf-enterprise/commercetools@2.0.2 - uses @vsf-enterprise/commercetools-api@~1.21.2

In addition, this is update path allows you to use @vsf-enterprise/commercetools with Node versions >= 16 (which includes Node 18).

Migration steps

  1. Update the @vsf-enterprise/commercetools package to 2.0.2
yarn add @vsf-enterprise/commercetools@2.0.2
  1. Upgrade the nuxt package to at least 2.16.2. Without it, you will get errors regarding hash generation when using Node 18.
$ yarn add nuxt@^2.16.2
  1. Update the Nuxt plugins to the versions that support Node 18. Only run those commands that update the packages that you actually have installed in your repository.

Only run those commands that update the packages that you actually have installed in your repository.

yarn add @vue-storefront/middleware@2.8.0
yarn add @vue-storefront/nuxt@2.8.0
yarn add @vue-storefront/nuxt-theme@2.8.0
yarn add @vue-storefront/cache@2.8.0
yarn add @vue-storefront/http-cache@2.8.0
yarn add @vue-storefront/health-check@2.8.0

If due to a mistake you have @vue-storefront/core installed explicitly (shouldn't happen)

yarn add @vue-storefront/core@2.8.0
  1. If your package.json file has the engines field, update it to reflect the currently supported Node versions:
      "engines": {
    -    "node": ">=14 <=16"
    +    "node": ">=16 <19"
      },
    

If you use the useStore composable be aware that:

  • The first argument to useStores().load(...) now has the type StoresWhereSearch. The new format is:
- useStore().load({ customQuery: { someMethod: 'some-custom-query' })
+ useStore().load({ id: 'id' });
+ useStore().load({ ids: ['id1', 'id2'] });
+ useStore().load({ key: 'key' });
  • The argument type change also means that useStores().load() method no longer accepts a customQuery parameter.

If you rely on the CustomQuery type, you'll need to update the package that it's imported from:

- import { CustomQuery } from '@vue-storefront/core';
+ import { CustomQuery } from '@vsf-enterprise/commercetools-api';

If after upgrading to v2.x you still intend to use Node 16 instead of the newer Node 18, please make sure to set the NODE_OPTIONS=--openssl-legacy-provider environment variable when launching your application. Otherwise, the launching will fail with an error. This workaround would not be necessary when using Webpack v5, however Nuxt 2 only supports up to Webpack 4. If you want to avoid this workaround, consider upgrading to Nuxt 3 and the Vue Storefront SDK (composables are not compatible with Nuxt 3).