Vue Storefront is now Alokai! Learn More
Custom Modules

Custom Modules

The SDK ships with a built-in middlewareModule that covers most use cases — communicating with the Server Middleware. When you need behavior that doesn't involve the middleware at all (a logger, an analytics tracker, a direct third-party API client), you can build a custom module instead.

When is a custom module necessary?

You can customize the built-in module's behavior by extending it. A custom module is only needed when the module communicates with a third-party service directly and shouldn't reach the Server Middleware at all.

Module structure

A module is a factory function that returns an object with three parts:

  • connector — the module's public methods.
  • utils — helper functions exposed alongside the connector.
  • subscribers — callbacks triggered by SDK events.

Create a new directory sdk/modules/logger, then add a module.ts file:

module.ts
import { Module } from "@alokai/connect/sdk";

export const loggerModule = () => {
  return {
    connector: {},
    utils: {},
    subscribers: {},
  } satisfies Module;
};

Connector

The connector holds the module's public methods. Start by adding a simple log method:

module.ts
import { Module } from "@alokai/connect/sdk";

export const loggerModule = () => {
  return {
    connector: {
      log: (message: string) => {
        console.log(message);
      },
    },
    utils: {},
    subscribers: {},
  } satisfies Module;
};

Extracting the connector

As the module grows, move the connector into its own file to keep things organized:

connector.ts
import { Connector } from "@alokai/connect/sdk";

export const loggerConnector = () => {
  return {
    log: (message: string) => {
      console.log(message);
    },
  } satisfies Connector;
};

Then import it in the module:

module.ts
import { Module } from "@alokai/connect/sdk";
import { loggerConnector } from "./connector";

export const loggerModule = () => {
  return {
    connector: loggerConnector(),
    utils: {},
    subscribers: {},
  } satisfies Module;
};

Methods

For even better separation, extract individual methods into a methods.ts file:

methods.ts
export const log = (message: string) => {
  console.log(message);
};

Spread them into the connector:

connector.ts
import { Connector } from "@alokai/connect/sdk";
import * as methods from "./methods";

export const loggerConnector = () => {
  return {
    ...methods,
  } satisfies Connector;
};

Methods can contain any logic you need. For example, sending logs to a remote server:

methods.ts
export const log = (message: string) => {
  console.log(message);
  fetch("https://example.com/log", {
    method: "POST",
    body: JSON.stringify({ message }),
  });
};

Utils

Utils are helper functions exposed alongside the connector. For example, a message formatter that adds a timestamp:

module.ts
import { Module } from "@alokai/connect/sdk";
import { loggerConnector } from "./connector";

export const loggerModule = () => {
  return {
    connector: loggerConnector(),
    utils: {
      formatMessage: (message: string) => {
        return `${new Date().toISOString()} - ${message}`;
      },
    },
    subscribers: {},
  } satisfies Module;
};

Subscribers

Subscribers react to SDK events. For example, the following subscriber sends a log to the server after every SDK method call across all modules. Learn more in the Subscribers docs.

module.ts
import { Module } from "@alokai/connect/sdk";
import { loggerConnector } from "./connector";

export const loggerModule = () => {
  return {
    connector: loggerConnector(),
    utils: {
      formatMessage: (message: string) => {
        return `${new Date().toISOString()} - ${message}`;
      },
    },
    subscribers: {
      "*_after": (payload) => {
        fetch("https://example.com/log", {
          method: "POST",
          body: JSON.stringify(payload),
        });
      },
    },
  } satisfies Module;
};

Registering the module

Wrap the module with defineSdkModule and export it from the modules directory:

sdk/modules/logger/index.ts
import { defineSdkModule } from "@vue-storefront/next";
import { loggerModule } from "./module";

export const logger = defineSdkModule(({ buildModule }) =>
  buildModule(loggerModule)
);

Then export it from sdk/modules/index.ts:

sdk/modules/index.ts
// ... other module exports
export * from "@/sdk/modules/logger";

Usage

Once registered, the module is available through the SDK:

const message = sdk.logger.utils.formatMessage("Hello, World!");
sdk.logger.log(message); // 2021-01-01T00:00:00.000Z - Hello, World!