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 Alokai 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 Alokai 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: Usesdk.ct.isLoggedIn() - Case: URLs that use
addBasePath()from the@vue-storefront/corepackage Migration: Prepend the result of callinguseRouter().options.baseto the URLs - Case:
useVSFContext().$ct.config.countriesMigration: If your store is restricted to particular countries, set them in Merchant Center on the URLhttps://mc.[region].gcp.commercetools.com/[project name]/settings/project/stores/[store id], then usesdk.ct.getStores()to fetch those countries. - Case:
onSSRMigration: UseuseAsyncanduseFetchfrom@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
- Remove the following packages:
yarn remove @vsf-enterprise/commercetools @vue-storefront/http-cache @vue-storefront/nuxt - 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 ashttp://localhost:4000/ct/getProduct.buildModules: [ '@nuxtjs/pwa', - [ - '@vsf-enterprise/commercetools/nuxt', - ... - ], - [ - '@vue-storefront/nuxt', - ... - ], ], modules: [ - [ - '@vue-storefront/http-cache/nuxt', - ... - ] ] - Install the
@vue-storefront/sdk,@vue-storefront/middleware,@vsf-enterprise/commercetools-sdkand@vsf-enterprise/commercetools-apipackagesyarn add @vue-storefront/sdk @vsf-enterprise/commercetools-sdk @vsf-enterprise/commercetools-api @vue-storefront/middleware{type='info'}
@vsf-enterprise/commercetools-apisince version1.19.0requires 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 ofsetup()to the Vue instance.
In case you run into issues withnode-gypmissing when installing, please runyarn global add node-gypand try again. - Upgrade the
nuxtpackage to at least2.16.2. Without it, you will get errors regarding hash generation when using Node 18.
yarn add nuxt@^2.16.2
- 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'],
}
- If your
package.jsonfile has theenginesfield, update it to reflect the currently supported Node versions:"engines": { - "node": ">=14 <=16" + "node": ">=16 <19" }, - In the repository root (or the
src/folder), create asdk.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 theapiUrlandssrApiUrlmatch the extension name that you used for the Commercetools integration in theintegrationsproperty inmiddleware.config.js:// middleware.config.js module.exports = { integrations: { ct: { location: '@vsf-enterprise/commercetools-api/server',
If the key in theintegrationsobject for you is for examplecommercetoolsinstead ofct, theapiUrlandssrApiUrlproperties should end with/commercetools.
Once thesdk.config.tsfile is created, you can then import the SDK to use in place of composables and getters in your.vuecomponents as previously shown in the introduction to this document:import { sdk } from "../sdk"; ... const products = await sdk.ct.getProduct({ id: productId }); ... - 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.3- 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
- Update the
@vsf-enterprise/commercetoolspackage to 2.0.3
yarn add @vsf-enterprise/commercetools@2.0.3
- Upgrade the
nuxtpackage to at least2.16.2. Without it, you will get errors regarding hash generation when using Node 18.
$ yarn add nuxt@^2.16.2
- 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
- If your
package.jsonfile has theenginesfield, 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 acustomQueryparameter.
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 Alokai SDK (composables are not compatible with Nuxt 3).