Vue Storefront is now Alokai! Learn More
Change Log

Change Log

4.1.0

Minor Changes

  • ADDED A new onContainerItemUpdated() callback can now be passed when calling the initLivePreview() utility. It is executed every time a Container Item is updated in the Experience Manager and receives the updated raw page object as the only argument. The updated page object can be normalized and used to re-render the Storefront page. See the example implementation below.

Keep in mind the unified normalizePage endpoint is available since @vsf-enterprise/bloomreach-content-api@2.1.0.

NextJS

apps/storefront-unified-nextjs/sf-modules/cms-bloomreach-content/components/live-preview.tsx

"use client";

import type { PageModel as BloomreachPageModel } from "@bloomreach/spa-sdk";
import { ReactNode, useEffect, useState } from "react";

import { useSdk } from "@/sdk/alokai-context";

export interface LivePreviewProps {
  page: BloomreachPageModel;
  render: (page: Record<string, any>) => Promise<ReactNode>;
}

export default function LivePreview({ page, render }: LivePreviewProps) {
  const sdk = useSdk();
  const [previewContent, setPreviewContent] = useState<ReactNode>(null);

  useEffect(() => {
    sdk.cms.utils.initLivePreview({
      onContainerItemUpdated: async (page) => {
        const normalizedPage = await sdk.unifiedCms.normalizePage({ page });
        const updatedContent = await render(normalizedPage);
        setPreviewContent(updatedContent);
      },
      page,
    });
  }, []);

  useEffect(() => {
    const ssrContent = document.getElementById("ssr-content");
    if (!previewContent) return;

    if (ssrContent) {
      /**
       * Hide the old SSR content when the preview is ready
       */
      ssrContent.style.display = "none";
    }
  }, [previewContent]);

  return previewContent;
}

apps/storefront-unified-nextjs/sf-modules/cms-bloomreach-content/components/connect-cms-page.tsx

import type { ComponentType } from "react";

import { logger } from "@/sdk/logger";
import { getSdk } from "@/sdk/sdk.server";

import LivePreview from "./live-preview";

export type PropsWithCmsPage<TPage = Record<string, any>> = {
  page: TPage;
  params: {
    locale: string;
  };
};

interface ConnectCmsPageParams<TProps> {
  getCmsPagePath: (props: TProps) => Promise<string> | string;
}

const componentsByPath: Record<string, ComponentType<any>> = {};

const appLocaleToCmsLocale: Record<string, string> = {
  de: "de",
  en: "en",
};

/**
 * Connects a CMS page to a Next.js page component
 */
export default function connectCmsPage<TProps>(
  PageComponent: ComponentType<TProps>,
  { getCmsPagePath }: ConnectCmsPageParams<TProps>
) {
  async function CmsPage(props: any) {
    const sdk = getSdk();
    const path = await getCmsPagePath(props);
    const { params, searchParams } = props;
    const { locale } = params;
    const cmsLocale = appLocaleToCmsLocale[locale];

    componentsByPath[path] = PageComponent;

    const page = await sdk.unifiedCms
      .getPage({
        locale: cmsLocale,
        path,
        searchParams: {
          ...searchParams,
          maxRefLevel: 4,
        },
      })
      .catch((error: unknown) => logger.error(error));

    if (!page) {
      return <PageComponent {...props} page={null} />;
    }

    async function render(page: Record<string, any>) {
      "use server";
      const PageComponent = componentsByPath[path];

      return <PageComponent {...props} page={page} />;
    }

    return (
      <>
        <LivePreview page={page.$raw} render={render} />
        <div id="ssr-content">{render(page)}</div>
      </>
    );
  }

  return CmsPage;
}

Nuxt

apps/storefront-unified-nuxt/sf-modules/cms-bloomreach-content/composables/useCmsPage/useCmsPage.ts

export function useCmsPage<TPage = any>() {
  const sdk = useSdk();
  const { path, query: searchParams } = useRoute();
  const { locale } = storeToRefs(useSfState());
  const { stripLocalePath } = useLocation();
  const page: Ref<null | TPage> = useState(() => null);

  const rawPage = computed(() => (page.value as any)?.$raw);

  async function getPage() {
    const cmsPage = await sdk.unifiedCms.getPage({
      locale: resolveCmsLocale(locale.value),
      path: stripLocalePath(path),
      searchParams,
    });
    page.value = cmsPage;
    return cmsPage;
  }

  function initLivePreview() {
    if (!rawPage.value) return;
    sdk.cms.utils.initLivePreview({
      onContainerItemUpdated: async (updatedPage) => {
        page.value = await sdk.unifiedCms.normalizePage({ page: updatedPage });
      },
      page: rawPage.value,
    });
  }

  return { getPage, initLivePreview, page };
}

function resolveCmsLocale(appLocale = "en") {
  const appLocaleToCmsLocale: Record<string, string> = {
    de: "de",
    en: "en",
  };
  return appLocaleToCmsLocale[appLocale] ?? "en";
}

Patch Changes

  • FIXED Retrieving document for a DOM node.
  • FIXED Selecting document with magnifying glass button.
  • Updated dependencies:
    • @vsf-enterprise/bloomreach-content-api@2.1.0

4.1.0-rc.2

Patch Changes

  • FIXED Selecting document with magnifying glass button.

4.1.0-rc.1

Patch Changes

  • FIXED Retrieving document for a DOM node.

4.1.0-rc.0

Minor Changes

  • ADDED A new onContainerItemUpdated() callback can now be passed when calling the initLivePreview() utility. It is executed every time a Container Item is updated in the Experience Manager and receives the updated raw page object as the only argument. The updated page object can be normalized and used to re-render the Storefront page. See the example implementation below.

Keep in mind the unified normalizePage endpoint is available since @vsf-enterprise/bloomreach-content-api@2.1.0.

NextJS

apps/storefront-unified-nextjs/sf-modules/cms-bloomreach-content/components/live-preview.tsx

"use client";

import type { PageModel as BloomreachPageModel } from "@bloomreach/spa-sdk";
import { ReactNode, useEffect, useState } from "react";

import { useSdk } from "@/sdk/alokai-context";

export interface LivePreviewProps {
  page: BloomreachPageModel;
  render: (page: Record<string, any>) => Promise<ReactNode>;
}

export default function LivePreview({ page, render }: LivePreviewProps) {
  const sdk = useSdk();
  const [previewContent, setPreviewContent] = useState<ReactNode>(null);

  useEffect(() => {
    sdk.cms.utils.initLivePreview({
      onContainerItemUpdated: async (page) => {
        const normalizedPage = await sdk.unifiedCms.normalizePage({ page });
        const updatedContent = await render(normalizedPage);
        setPreviewContent(updatedContent);
      },
      page,
    });
  }, []);

  useEffect(() => {
    const ssrContent = document.getElementById("ssr-content");
    if (!previewContent) return;

    if (ssrContent) {
      /**
       * Hide the old SSR content when the preview is ready
       */
      ssrContent.style.display = "none";
    }
  }, [previewContent]);

  return previewContent;
}

apps/storefront-unified-nextjs/sf-modules/cms-bloomreach-content/components/connect-cms-page.tsx

import type { ComponentType } from "react";

import { logger } from "@/sdk/logger";
import { getSdk } from "@/sdk/sdk.server";

import LivePreview from "./live-preview";

export type PropsWithCmsPage<TPage = Record<string, any>> = {
  page: TPage;
  params: {
    locale: string;
  };
};

interface ConnectCmsPageParams<TProps> {
  getCmsPagePath: (props: TProps) => Promise<string> | string;
}

const componentsByPath: Record<string, ComponentType<any>> = {};

const appLocaleToCmsLocale: Record<string, string> = {
  de: "de",
  en: "en",
};

/**
 * Connects a CMS page to a Next.js page component
 */
export default function connectCmsPage<TProps>(
  PageComponent: ComponentType<TProps>,
  { getCmsPagePath }: ConnectCmsPageParams<TProps>
) {
  async function CmsPage(props: any) {
    const sdk = getSdk();
    const path = await getCmsPagePath(props);
    const { params, searchParams } = props;
    const { locale } = params;
    const cmsLocale = appLocaleToCmsLocale[locale];

    componentsByPath[path] = PageComponent;

    const page = await sdk.unifiedCms
      .getPage({
        locale: cmsLocale,
        path,
        searchParams: {
          ...searchParams,
          maxRefLevel: 4,
        },
      })
      .catch((error: unknown) => logger.error(error));

    if (!page) {
      return <PageComponent {...props} page={null} />;
    }

    async function render(page: Record<string, any>) {
      "use server";
      const PageComponent = componentsByPath[path];

      return <PageComponent {...props} page={page} />;
    }

    return (
      <>
        <LivePreview page={page.$raw} render={render} />
        <div id="ssr-content">{render(page)}</div>
      </>
    );
  }

  return CmsPage;
}

Nuxt

apps/storefront-unified-nuxt/sf-modules/cms-bloomreach-content/composables/useCmsPage/useCmsPage.ts

export function useCmsPage<TPage = any>() {
  const sdk = useSdk();
  const { path, query: searchParams } = useRoute();
  const { locale } = storeToRefs(useSfState());
  const { stripLocalePath } = useLocation();
  const page: Ref<null | TPage> = useState(() => null);

  const rawPage = computed(() => (page.value as any)?.$raw);

  async function getPage() {
    const cmsPage = await sdk.unifiedCms.getPage({
      locale: resolveCmsLocale(locale.value),
      path: stripLocalePath(path),
      searchParams,
    });
    page.value = cmsPage;
    return cmsPage;
  }

  function initLivePreview() {
    if (!rawPage.value) return;
    sdk.cms.utils.initLivePreview({
      onContainerItemUpdated: async (updatedPage) => {
        page.value = await sdk.unifiedCms.normalizePage({ page: updatedPage });
      },
      page: rawPage.value,
    });
  }

  return { getPage, initLivePreview, page };
}

function resolveCmsLocale(appLocale = "en") {
  const appLocaleToCmsLocale: Record<string, string> = {
    de: "de",
    en: "en",
  };
  return appLocaleToCmsLocale[appLocale] ?? "en";
}

Patch Changes

  • Updated dependencies:
    • @vsf-enterprise/bloomreach-content-api@2.1.0-rc.0

4.0.2

Patch Changes

  • Updated dependencies:
    • @vsf-enterprise/bloomreach-content-api@2.0.0

4.0.1

Patch Changes

  • Updated dependencies:
    • @vsf-enterprise/cms-components-utils@2.0.0

4.0.0

Major Changes

  • CHANGED The interface of the connectFunctions has changed. Now they give you access to:
  • context as the first argument,
  • experienceElement as the second argument,
  • HTML node as the third argument.

If you were customizing the connectFunctions, please update your implementation accordingly:

const sdk = useSdk();

sdk.cms.utils.initLivePreview({
  page: rawPage.value,
  connectFunctions: {
-   connectComponent: (experienceComponent, context) => {},
+   connectComponent: (context, experienceComponent, node) => {},
-   connectDocument: (experienceDocument, context) => {},
+   connectDocument: (context, experienceDocument, node) => {},
-   connectContainer: (experienceContainer, context) => {},
+   connectContainer: (context, experienceContainer, node) => {},
-   connectContainerItem: (experienceContainerItem, context) => {},
+   connectContainerItem: (context, experienceContainerItem, node) => {},
-   connectRootComponent: (experienceRootComponent, node) => {},
+   connectRootComponent: (context, experienceRootComponent, node) => {},
  }
});

// before

//after
sdk.utils.

3.2.0

Minor Changes

  • ADDED New initLivePreview() utility for initializing the connection with the Experience Manager. See the method's TSDoc for more information.

3.1.0

Minor Changes

  • CHANGED The extractComponents utility has been marked as @deprecated and will be removed in 4 years from now (July 2028). Use getPage method which returns unified CMS page data.
- const extractedData = sdk.bloomreachContent.utils.extractComponents(params);
+ const extractedData = sdk.unifiedCms.getPage(params);

3.1.0-rc.0

Minor Changes

  • ADDED New initLivePreview() utility for initializing the connection with the Experience Manager. See the method's TSDoc for more information.

3.0.0

Major Changes

  • ADDED Implemented Alokai's middlewareModule. The module can now connect to endpoints exposed by a newly created @vsf-enterprise/bloomreach-content-api package. Make sure you add apiUrl to the module's configuration and install @vsf-enterprise/bloomreach-content-api in your Server Middleware.

2.1.0

Minor Changes

  • CHANGED Updated @bloomreach/spa-sdk version to 23.3.0.

2.0.1

Patch Changes

Update axios to ^0.28.0 to mitigate security vulnerability CVE-2023-45857

2.0.0

Major Changes

  • CHANGED Changed minimum Node version from 16 to 18. The condition that was forcing the Node version to be lower than 19 is also removed.

1.0.0