Change Log
4.1.0
Minor Changes
- ADDED A new
onContainerItemUpdated()
callback can now be passed when calling theinitLivePreview()
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 theinitLivePreview()
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). UsegetPage
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 addapiUrl
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 to23.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.