@commercetools-labs/page-builder
v1.0.0
Published
Storefront shim for the page-builder service: one <PageBuilder> mount that fetches the render tree, renders the grid with self-contained CSS, and ships the visual-editing bridge. No commercetools access in the host.
Maintainers
Readme
@commercetools-labs/page-builder
The storefront side of the page-builder: one <PageBuilder> mount, a component map and a catalog file.
Everything else (reading pages, drafts, preview gating, data resolution, localisation, layout packing)
happens in the per-project page-builder service. The host holds no
commercetools credentials, no resolvers and no Tailwind setup.
Version 1.0 is a breaking rewrite of 0.x. defineBlock, buildCatalog, buildRegistry,
createPageBuilderSections, the page-builder CLI, block-level resolve functions and the host
CTP_* / PB_PREVIEW_TOKEN variables are gone. React / Next.js (App Router) only.
Integrate
Mount it. One route renders every page:
// app/[[...path]]/page.tsx import { PageBuilder } from '@commercetools-labs/page-builder'; import { components } from '@/components/blocks'; export default async function Page({ params, searchParams }) { const { path = [] } = await params; return ( <PageBuilder components={components} path={`/${path.join('/')}`} context={{ locale: 'en-US', currency: 'USD', country: 'US', store: 'my-store' }} searchParams={await searchParams} fallback={<NotFound />} // no page for this path; rendering `notFound()` gives a real 404 errorFallback={<Unavailable />} // service down or erroring; defaults to `fallback` /> ); }Map components.
componentsmaps a catalog componenttypeto a React component (server or client; async is fine). It receives{ data, editMode? }:datais the author's settings, already localised, with every data-source field and route-driven slice resolved by the service into the canonical shapes. UsePBText/Editablefor inline editing in the visual editor; they are inert outside edit mode.Describe the components.
page-builder.catalog.jsonlists the component types (with their editable fields), data sources (with a service-sideresolver.kind), sections and theme tokens. It validates againstcatalog.schema.json("$schema": "./node_modules/@commercetools-labs/page-builder/catalog.schema.json").Push it from CI. Validate on pull requests; push and publish after the deploy (see
examples/nextjs-storefront/scripts/catalog.mjs, which has no dependencies).Configure.
| Variable | | |---|---| |
PB_SERVICE_URL| the service URL including its Connect path, e.g.https://service-….commercetools.app/service| |PB_RENDER_KEY| the render key (required by the service in production) | |PB_ORIGIN| this storefront's public origin, sent asX-PB-Origin(a server-side fetch has no browserOrigin) | |PB_TIMEOUT_MS| render call timeout, default2000|All four can also be passed as props.
A working host is in examples/nextjs-storefront.
Behaviour
- Failure is a fallback, never stale content. A path with no page renders
fallback. A timeout, network error, rejected credentials, bad response or a misconfigured service URL renderserrorFallback(which defaults tofallback; either renders nothing when unset) and logs the reason. Only the service's ownpage_not_foundanswer counts as "no page": any other 404 is reported asbad_route, so a wrongPB_SERVICE_URLis not mistaken for a missing page. Use the two to show a 404 for a missing page and a "temporarily unavailable" page for an outage. There is no host-side cache; the service caches commercetools reads for 15 seconds. Page rendering is dynamic; do not wrap it in a cache. - Preview and visual editing need no host code. Forward
searchParams; the service validatespb_preview/pb_editand returns drafts, edit mode, the allowed Merchant Center origins and the component manifest. In edit mode the shim emits thedata-pb-*markers and mounts the bridge. - Self-contained styling. The 12-column grid, breakpoints (tablet ≥ 768px, desktop ≥ 1024px) and
per-device hiding are plain scoped CSS (
pb-*classes and CSS variables). Section backgrounds, container width and gaps come from the catalogtheme. - Wire versioning. Every call sends
X-PB-Wire-Version. A service that does not support it answers 426 with the versions it does; the shim renders the fallback and logs "upgrade the shim".
Develop
npm install --legacy-peer-deps # npm 10 crashes on this package's peer graph without it
npm test # vitest (shim behaviour, grid output, bridge protocol, wire-contract drift)
npm run test:coverage
npm run generate:api # regenerate wire types from ../../page-builder-service/openapi.yaml