This is the early access documentation preview for Custom Views. This documentation might not be in sync with our official documentation.
commercetools Frontend SDK
The commercetools Frontend SDK is an event management tool that allows flexible and customizable frontend development. It also allows creating custom integrations that are backend-agnostic and backward-compatible. The commercetools Frontend SDK can be extended with additional SDKs and integrations that expose commercetools Frontend API integrations.
Install and set up the SDK
The SDK is released as an npm package. To install it in your commercetools Frontend project, follow these steps:
- Run
yarn add @commercetools/frontend-sdk
. - Run
yarn add @commercetools/frontend-domain-types
. - Set up the SDK and any additional integration packages in the same location, as shown in the example below.
The SDK and its integrations must behave as singletons to prevent integrations from creating repeated events and multiple configuration calls.
It is recommended to use the latest version of all packages related to commercetools frontend SDK. The @commercetools/frontend-sdk
package will always be backward compatible, therefore having the latest version ensures you have all features and full compatibility with all your integrations.
Below is a template provided to use with the SDK and integrations to ensure singleton behaviour.
import { SDK } from '@commercetools/frontend-sdk';import {ComposableCommerce,ComposableCommerceEvents,} from '@commercetools/frontend-composable-commerce';// Add other integration's custom events to the SDK's generic type here,// by extending ComposableCommerceEvents with their type using an intersection.// For example, <ComposableCommerceEvents & OtherEvents>.// You may also add your own custom events.class CommercetoolsSDK extends SDK<ComposableCommerceEvents> {composableCommerce!: ComposableCommerce;// Add your other integrations here.constructor() {super();this.composableCommerce = new ComposableCommerce(this);// Initialize your other integrations here.this.on('errorCaught', (event) => {// Handle any integrations errors caught by the SDK globally.// For example, log error, fire notification, etc.console.log('SDK error: ', event.data);});// Set up any other custom global event handlers here.// Ensure types are created and added to the SDK generic type// if specific to your project.}}// Create a single instance of the SDK.const sdk = new CommercetoolsSDK();// Export only the instance to serve as a singleton throughout the project.export { sdk };
The previous example creates and exports an instance to ensure singleton behavior. However, the CommercetoolsSDK.ts
template file must be the single source of truth for anything related to the SDK and integrations. Therefore, it is recommended to store CommercetoolsSDK.ts
and index.ts
in a folder packages/<project>/frontend/sdk
for convention and ease of import.
import { sdk } from './CommercetoolsSDK';export { sdk };
Configure the SDK
Import and configure the SDK in an index location within your project, this needs to be called only once since the SDK is exported as a singleton. However, the SDK must be configured for both client-side and server-side rendering. The following example imports and configures the SDK in a Next.js project.
import { AppProps } from 'next/app';import { sdk } from '../sdk';sdk.configure({locale: 'de-DE',currency: 'EUR',endpoint: 'EXTENSION_RUNNER_HOSTNAME',});const Starter = ({ Component, pageProps }: AppProps) => {return <Component {...pageProps} />;};export default Starter;
For information on the extension runner hostname, see Main development concepts.
If needed, pass the useCurrencyInLocale
property to the configure
method. The default value is false
.
sdk.configure({locale: 'de-DE@EUR',currency: 'EUR',endpoint: 'EXTENSION_RUNNER_HOSTNAME',useCurrencyInLocale: true,});
You can import the configuration properties from the .env
file, a .config
file, or the getServerSideProps
call in Next.js for server-side rendering.
import { GetServerSideProps, Redirect } from 'next';import { mapSDKLanguage } from 'project.config';import { sdk } from '../sdk';type SlugProps = {...};export default function Slug({ data }: SlugProps) {...}export const getServerSideProps: GetServerSideProps | Redirect = async ({ params, locale, query, req, res }) => {sdk.configure({locale: mapSDKLanguage(locale),currency: 'EUR',endpoint: (process.env.NEXT_PUBLIC_FRONTASTIC_HOST ?? ”https://my.staging.server/frontastic”).split('/frontastic')[0],});...};
If the project uses only the SDK, no further configuration is required. If the project also uses integrations, you can call them from packages/<project>/frontend/sdk
.
The following example configures a Next.js project that uses the @commercetools/frontend-composable-commerce
integration. The getSettings
function is called on button click and applies the project settings. On component mount, the useEffect
React lifecycle hook adds an event handler to log the result of the fetch to the console. On component unmount, the event handler is cleaned up.
import { NextPage } from 'next';import React, { useEffect, useState } from 'react';import App from '../../components/App';import HorizontalSpacer from '../../components/horizontalSpacer';import { sdk } from '../../sdk';import Button from 'src/components/form/button';import { ProjectSettings } from '@commercetools/frontend-domain-types/ProjectSettings';const ExamplePage: NextPage = () => {const [projectSettings, setProjectSettings] = useState<ProjectSettings>();const [loading, setLoading] = useState(false);const projectSettingsReturnedEvent = (event: Event<'projectSettingsReturned',{settings: unknown;}>) => {// Access the commercetools Frontend project settings here.console.log('Event projectSettingsReturned fired: ', event.data.settings);};useEffect(() => {sdk.on('projectSettingsReturned', projectSettingsReturnedEvent);return () => {sdk.off('projectSettingsReturned', projectSettingsReturnedEvent);};}, []);const getSettings = async () => {setLoading(true);const response = await sdk.composableCommerce.project.getSettings();setLoading(false);if (response.isError === false) {setProjectSettings(response.data);}};const style = { fontWeight: 'bold', textDecoration: 'underline' };return (<App><><h1>Example</h1><HorizontalSpacer /><Buttontext="TEST"onSubmit={projectSettings ? () => setProjectSettings(undefined) : getSettings}loading={loading}/><HorizontalSpacer />{projectSettings && (<><><h2 style={style}>NAME</h2><p>{projectSettings.name}</p></></>)}</></App>);};export default ExamplePage;
The response.isError
in the getSettings
function must be explicitly compared to the boolean value in non-strict projects for the narrowing to work on the SDKResponse union type. Otherwise, the error Property 'data' does not exist on type
will occur on when accessing response.data
. For strict projects, a simple truthy/falsy comparison such as !response.isError
is sufficient.