首页
/ Next.js × Sitecore XM Cloud:基于 JSS 渲染 SDK 搭建 Headless CMS 站点的完整实践

Next.js × Sitecore XM Cloud:基于 JSS 渲染 SDK 搭建 Headless CMS 站点的完整实践

2026-09-06 16:12:31作者:虞亚竹Luna

本文基于 Next.js 官方仓库中的 cms-sitecore-xmcloud 示例 展开,讲解如何使用 Sitecore JavaScript Rendering SDK(JSS)将 Next.js 应用接入 Sitecore XM Cloud 站点,实现 headless SXA(Sitecore Experience Accelerator)组件渲染。读完后,你将掌握该示例所需的全部环境变量配置、create-next-app 脚手架与 npm 脚本用法、构建期 bootstrap 代码生成流程、Next.js 与 Sitecore 之间的请求重写策略,以及 SSG + ISR 的页面渲染模型,并理解 Sitecore 侧配置补丁如何与前端应用协同工作。

示例定位:JSS SDK + headless SXA

该示例是一个通过 Sitecore JSS for Next.js SDK 连接 Sitecore XM Cloud 站点的完整 Next.js 项目,内置了一组示例组件与 headless SXA 的配置。其核心特点(由 package.json 与源码可确认):

  • 依赖 @sitecore-jss/sitecore-jss-nextjs(约 21.1.6 版本)与 @sitecore-jss/sitecore-jss-cli,并基于 next ^13.1.6、react ^18.2.0 构建;
  • package.json 中的 config 字段声明了 JSS 应用身份:appNamexmcloud-nextjs-starter、根占位符 rootPlaceholdersjss-main、配置补丁部署路径 sitecoreConfigPath/App_Config/Include/zzz、GraphQL Edge 端点路径 graphQLEndpointPath/sitecore/api/graph/edge,并且 templates 同时包含 nextjsnextjs-sxa,即同时启用 JSS 基础模板与 headless SXA 模板;
  • 样式层引入了 bootstrap 5、font-awesome 与完整的 SASS 变体体系(见 src/assets),用于承载 headless SXA 组件的预设样式变体(如 promonavigationrich-text 等目录)。

关于如何从零创建并部署 XM Cloud 项目的完整流程,官方建议参考 Vercel 的 Sitecore XM Cloud 集成指南与 Sitecore 官方文档(示例 README 中的外部链接),本文则聚焦仓库内可直接验证的实现细节。

环境变量:连接 XM Cloud 的钥匙

示例 README 列出了部署时必须提供的 5 个环境变量,完整的 .env.example 还补充了若干开发期变量。逐一说明:

变量 作用 来源
JSS_APP_NAME 在 XM Cloud 中配置的 JSS 应用名称 README 要求必填
GRAPH_QL_ENDPOINT GraphQL Edge 端点,Sitecore Experience Edge 必需 README 要求必填
SITECORE_API_KEY Sitecore API Key,构建应用所必需 README 要求必填
SITECORE_API_HOST Sitecore API 主机名 README 要求必填
FETCH_WITH 获取 Sitecore API 数据的方式,取值为 GraphQLREST README 要求必填
PUBLIC_URL 用于绝对 URL 的公共地址(编辑器内运行 Next.js 应用时需要)。必须与 Sitecore 配置中的 serverSideRenderingEngineApplicationUrl 一致,随公共端点变化而更新 .env.example
JSS_EDITING_SECRET 保护 Sitecore 编辑器端点(默认 /api/editing/render)的密钥。该客户端值必须与服务端值(Sitecore 配置补丁中的 JavaScriptServices.ViewEngine.Http.JssEditingSecret)一致,建议至少 16 位字母数字 .env.example
DEFAULT_LANGUAGE 应用的默认语言 .env.example
DISABLE_SSG_FETCH 设置为 true 时跳过 getStaticPaths 的预渲染抓取,启用完整的 ISR(增量静态再生成)流程 .env.example
DEBUG Sitecore JSS 的 npm 包使用 debug 模块输出日志,如 DEBUG=sitecore-jss:* 查看全部日志,DEBUG=sitecore-jss:layout 只看 Layout Service 日志 .env.example

两点值得注意(均可在源码中验证):

  • SITECORE_API_KEYSITECORE_API_HOST 之所以被标注为“构建时必需”,是因为它们通常保存在 scjssconfig.json(分别为 sitecore.apiKeysitecore.layoutServiceHost),而该文件在本地从未执行过 jss setup、或处于忽略源码管理的更高环境时可能不存在,此时需要通过环境变量在构建期提供;
  • .env.example 明确提示 Next.js 原生支持 .env.local(且已加入 git 忽略),本地开发时应使用它存放敏感值。

脚手架与 npm 脚本

README 给出了通过 create-next-app 引导示例的三种方式:

npx create-next-app --example cms-sitecore-xmcloud cms-sitecore-xmcloud-app
yarn create next-app --example cms-sitecore-xmcloud cms-sitecore-xmcloud-app
pnpm create next-app --example cms-sitecore-xmcloud cms-sitecore-xmcloud-app

脚手架完成后,日常开发由 package.json 中的 scripts 驱动,核心命令如下:

命令 作用
npm run dev 等价于 cross-env NODE_OPTIONS='--inspect' next dev,带 Node 调试端口启动开发服务器
npm run start 等价于 next start,启动生产服务器
npm run jss 调用 Sitecore JSS CLI(jss),用于 setup、deploy config 等操作
npm run bootstrap 以 ts-node 运行 scripts/bootstrap.ts,生成构建所需的临时 JS 文件(见下节)
npm run build npm-run-all --serial bootstrap next:build,即先执行 bootstrap 再生成 Next.js 构建产物
npm run graphql:update 运行 scripts/fetch-graphql-introspection-data.ts,拉取 GraphQL 内省数据以更新类型定义
npm run scaffold 运行 scripts/scaffold-component.ts 生成新组件骨架
npm run start:connected 串行执行 bootstrap 后,并行启动 next devgenerate-component-factory.ts --watch,即“连接模式”:组件工厂随组件源码变化实时重新生成
npm run start:production 串行执行 bootstrap、next buildnext start

其中 start:connected 是该示例开发体验的关键:连接 Sitecore 本地站点时,sitecore-jss-cli 会持续监听组件目录并将组件名到 React 组件的映射写入工厂文件,保证 Editor 中新增/重命名组件后无需重启即可被前端识别。

构建期 bootstrap:插件、配置与组件工厂的代码生成

build 命令之所以先跑 bootstrap,是因为 Next.js 需要导入一批在构建前动态生成的模块。从 scripts/bootstrap.ts 可以看到它依次执行三个阶段:

  1. 插件生成generate-plugins.ts):按约定扫描各 src/lib/*/plugins 目录,自动生成 src/temp 下的插件清单模块。示例中定义了 7 组插件映射,覆盖了 config、sitemap-fetcher、middleware、page-props-factory、next-config、extract-path、site-resolver 七个工厂。命名约定是:文件名去掉扩展名后,按连字符大驼峰化并追加 Plugin 后缀(如 preview-mode.ts 映射为 previewModePlugin)。这套机制意味着后续扩展页面 props 的处理逻辑时,只需在对应 plugins 目录下新增文件即可自动注册;
  2. 配置生成generate-config.ts):将运行时配置写入 src/temp/config.js。值得注意的是其写入策略——每个配置项都生成为 config.xxx = process.env.XXX || '<默认值>' 的形式,即环境变量优先、默认值兜底,这也是为什么 SITECORE_API_KEY 等值既能写进 scjssconfig.json 也能通过环境变量注入;
  3. 组件工厂生成generate-component-factory.ts):生成 temp/componentFactory,提供 componentFactory(生产渲染)与 editingComponentFactory(编辑器渲染)两套组件名到组件的映射。

Next.js 与 Sitecore 的集成:重写、国际化与资源前缀

next.config.js 是前后端集成的枢纽,值得逐项拆解:

const jssConfig = require("./src/temp/config");
const { getPublicUrl } = require("@sitecore-jss/sitecore-jss-nextjs");
const plugins = require("./src/temp/next-config-plugins") || {};
const publicUrl = getPublicUrl();

const nextConfig = {
  assetPrefix: publicUrl,
  distDir: process.env.NEXTJS_DIST_DIR || ".next",
  env: {
    PUBLIC_URL: publicUrl,
  },
  i18n: {
    locales: ["en"],
    defaultLocale: jssConfig.defaultLanguage,
  },
  reactStrictMode: true,
  async rewrites() {
    // 连接模式下将 Sitecore 路径代理到 Sitecore
    return [
      { source: "/sitecore/api/:path*", destination: `${jssConfig.sitecoreApiHost}/sitecore/api/:path*` },
      { source: "/-/:path*", destination: `${jssConfig.sitecoreApiHost}/-/:path*` },
      { source: "/layouts/system/:path*", destination: `${jssConfig.sitecoreApiHost}/layouts/system/:path*` },
      { source: "/healthz", destination: "/api/healthz" },
      { source: "/sitecore/service/:path*", destination: `${jssConfig.sitecoreApiHost}/sitecore/service/:path*` },
    ];
  },
};

module.exports = () => {
  return Object.values(plugins).reduce((acc, plugin) => plugin(acc), nextConfig);
};

几个设计要点:

  • 重写规则是“连接模式”(connected mode)的核心:/sitecore/api/* 代理 Layout Service 等 API,/-/* 代理媒体文件,/layouts/system/* 用于访客识别(visitor identification),/sitecore/service/* 代理 Sitecore 服务页面。结合 Sitecore 配置中 IncludeServerUrlInMediaUrls=false 的设置,媒体请求全部经由 Next.js 转发,避免把 Sitecore 服务器直接暴露给公网
  • i18n 路由locales 应覆盖(或为子集于)Sitecore 中配置的语言,访问不带语言前缀的路径时回落到 defaultLanguage
  • 插件化的配置导出module.exports 是一个函数,会把 nextConfig 依次交给 src/temp/next-config-plugins 中的插件变换。查看 src/lib/next-config/plugins 目录可知内置了 graphql.jsrobots.jssass.jssitemap.js 四个插件,分别负责注入 GraphQL 端点处理、robots.txt 与 sitemap 生成、SASS 编译等构建行为;
  • NEXTJS_DIST_DIR 允许在容器化并发运行时指定不同的产物目录。

渲染模型:Catch-all 路由 + SSG + ISR

示例采用 Pages Router 的单一 catch-all 页面承载整个站点:src/pages/[[...path]].tsx 负责所有路径的渲染。其数据获取逻辑体现了 SSG 与 ISR 的组合使用:

export const getStaticPaths: GetStaticPaths = async (context) => {
  let paths: StaticPath[] = [];
  let fallback: boolean | "blocking" = "blocking";

  if (process.env.NODE_ENV !== "development" && !process.env.DISABLE_SSG_FETCH) {
    try {
      // 生产/构建模式下,从 Sitecore 抓取站点地图以预渲染全部页面
      paths = await sitemapFetcher.fetch(context);
    } catch (error) {
      console.log("Error occurred while fetching static paths");
    }
    fallback = process.env.EXPORT_MODE ? false : fallback;
  }

  return { paths, fallback };
};

export const getStaticProps: GetStaticProps = async (context) => {
  const props = await sitecorePagePropsFactory.create(context);
  return {
    props,
    // 最多每 5 秒重新生成一次
    revalidate: 5,
    notFound: props.notFound,
  };
};

从源码结构看,这个策略是双模式的:

  • 构建/生产模式下(非 development 且未设置 DISABLE_SSG_FETCH),sitemapFetcher(其插件位于 src/lib/sitemap-fetcher/plugins/graphql-sitemap-service.ts)会向 Sitecore 请求站点地图,把所有页面路径作为 getStaticPaths 的返回值预先静态渲染
  • 开发模式或显式设置 DISABLE_SSG_FETCH=true 时,返回空 paths + fallback: "blocking",所有页面按需渲染,配合 revalidate: 5 形成完整的 ISR 流程——请求到来时若页面过期则阻塞并重新生成。

页面组件本身还处理了两种编辑态:

  • pageEditing 为 true 时切换到 editingComponentFactory
  • renderingType === RenderingType.Component 时渲染 EditingComponentPlaceholder,即组件级渲染——Sitecore 编辑器修改单个组件时无需刷新整页;
  • 由于 Sitecore 编辑器不支持 Fast Refresh,页面挂载后通过 handleEditorFastRefresh() 在快速刷新完成后刷新编辑器 chrome。

页面 props 由 sitecorePagePropsFactory 生成,其插件目录 src/lib/page-props-factory/plugins 包含 component-propsnormal-modepreview-modesite 四个插件,分别负责组件 props 解析、普通模式取数、预览模式取数与站点信息注入——预览模式与正常模式走不同取数路径,正是编辑器实时预览与生产渲染分离的实现基础。

数据获取:GraphQL 或 REST

.env.exampleFETCH_WITH 默认取值为 GraphQL。该示例的取数实现是 src/lib/data-fetcher.ts

import { AxiosDataFetcher, AxiosResponse } from "@sitecore-jss/sitecore-jss-nextjs";

export function dataFetcher<ResponseType>(
  url: string,
  data?: unknown,
): Promise<AxiosResponse<ResponseType>> {
  return new AxiosDataFetcher().fetch<ResponseType>(url, data);
}

它基于 SDK 提供的 AxiosDataFetcher,源码注释明确说明这是一个可替换的实现——只要符合 HttpDataFetcher<T> 的约束,即可换成任意支持 SSR 的 HTTP/fetch 库。Layout 与 Dictionary 数据则分别由 layout-service-factory.tsdictionary-service-factory.ts 根据 FETCH_WITH 选择 GraphQL 或 REST 通道。多语言字典通过 src/pages/_app.tsx 中的 next-localization(Rossetta)注入 I18nProvider,源码注释也提醒:Next.js 只提供 i18n 路由而不提供翻译能力,单语言应用可移除相关引用。

此外,src/pages/api 下还实现了四个 API 路由:editing/render.ts(编辑器渲染端点,受 JSS_EDITING_SECRET 保护)、healthz.ts(健康检查,供 rewrites 中的 /healthz 转发命中)、robots.tssitemap.ts(由 next-config 插件接管生成)。

Sitecore 侧配置补丁与前端的双向约定

前端的种种行为在 Sitecore 侧有对应约定,见配置补丁 sitecore/config/xmcloud-nextjs-starter.config。该文件由 jss deploy config 部署(目标路径取自 package.json 的 sitecoreConfigPath,即 /App_Config/Include/zzz),关键内容包括:

  1. 站点注册<sites> 节点):注册名为 xmcloud-nextjs-starter 的站点,hostNamexmcloud-nextjs-starter.dev.localrootPath/sitecore/content/xmcloud-nextjs-starterstartItem/home。注释特别强调:JSS 站点默认以 live 模式运行(database="master"),便于开发但禁用了 workflow 与发布,上线前必须改为 web
  2. JSS 应用注册<javaScriptServices><apps> 节点):
    • graphQLEndpoint="/sitecore/api/graph/edge" 启用 Integrated GraphQL,不用可移除;
    • layoutServiceConfiguration 使用 GraphQL Edge schema 时应为 default
    • serverSideRenderingEngineEndpointUrl="http://localhost:3000/api/editing/render" 指向前端的编辑器端点,serverSideRenderingEngineApplicationUrl="http://localhost:3000" 必须与环境变量 PUBLIC_URL 一致——这就是 .env.example 中反复强调“随公共端点变化而更新”的原因。
  3. 媒体缩放白名单<allowedMediaParams>):JSS 的服务端媒体缩放(<Image/> 帮助组件的 imageParams/srcSet props)要求参数集合白名单化以防 DoS 攻击。示例中提供了 styleguide-image-samplemw=100,mh=50)与 next-image-default(对应 Next.js 图片组件的默认宽度集合:16、32、48、64、96、128、256、384、640、750、828、1080、1200、1920、2048、3840)两组,未在白名单中的参数组合将返回未缩放的原始图片;
  4. 媒体 URL 解析<layoutService> 节点):对 default(GraphQL Edge 请求)与 jss(Layout Service REST 请求)两套配置均设置 IncludeServerUrlInMediaUrls=false,让媒体请求不带 Sitecore 服务器 URL,从而全部走 Next.js 的 rewrites 转发,避免直接暴露 Sitecore 服务器;
  5. 可选设置:Analytics.ForwardedRequestHttpHeader(让分析模块读取 X-Forwarded-For 以记录真实客户端 IP)、开发期机器人检测开关、Experience Edge 的 item/field 级语言回退开关。

内置的 headless SXA 组件

src/components 目录随示例提供了一组 headless SXA 渲染组件,可直接作为组件开发模板参考:

  • 基础布局ContainerPageContentTitlePromoNavigationRichTextLinkListImage
  • SXA 分割器RowSplitterColumnSplitter(配合 ContentBlock 处理 SXA 布局块);
  • 动态占位符PartialDesignDynamicPlaceholder(承载 SXA partial design 的动态内容区域);
  • 前端即服务(FEaaS)包装FEaaSWrapper(Sitecore FEaaS 场景下的容器组件)。

这些组件对应 templates 中的 nextjs-sxa 模板产物,SXA 组件的预设样式变体则集中在 src/assets/sass/variantslink-listnavigationpage-contentpromorich-texttitle 六个变体目录)。新组件可通过 npm run scaffold 脚手架生成,并以 npm run start:connected 在连接模式下热更新组件工厂。

小结与相关示例

回顾该示例的完整工作链路:bootstrap 在构建前生成插件清单、运行时配置(环境变量优先)与组件工厂 → next.config.js 完成重写代理、i18n 与插件化配置 → catch-all 页面通过 sitemapFetcher 预取路径实现 SSG,或以 fallback: "blocking" + revalidate: 5 走 ISR → page-props-factory 区分正常/预览模式取数 → 编辑器端点 /api/editing/renderJSS_EDITING_SECRET 保护并支持组件级局部刷新。整条链路的前后端契约(API 主机、应用名、编辑端点、媒体白名单)由环境变量与 Sitecore 配置补丁共同维护,两侧取值必须严格一致。

Next.js 仓库的 examples 目录下还有大量其他 CMS 集成示例可作对照参考:AgilityCMSBuilder.ioButterCMSContentfulCosmicDatoCMSDotCMSDrupalEnterspeedGhostGraphCMSKontent.aiMakeSwiftPayloadPlasmicPreprPrismicSanitySitefinityStoryblokTakeShapeTinaUmbracoUmbraco HeartcoreWebinyWordPress 以及 Blog Starter

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391