Next.js 与 Payload 同仓 Serverless 部署:@payloadcms/next-payload 集成实战

📅 发布时间:2026/9/7 18:56:16
Next.js 与 Payload 同仓 Serverless 部署:@payloadcms/next-payload 集成实战 Next.js 与 Payload 同仓 Serverless 部署payloadcms/next-payload 集成实战【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js本篇指南围绕 Next.js 仓库中的 cms-payload 示例 展开讲解如何使用payloadcms/next-payload将 Payload CMS 以 Serverless 方式与 Next.js 应用部署在同一个仓库中涵盖本地开发启动流程、所需环境变量、withPayload配置改造、Admin 界面挂载位置以及内容变更触发页面按需再水合的完整链路。读完之后你可以独立搭建一套「Next.js 前端 Payload 内容管理」的同仓部署方案并理解其背后的实现机制。方案定位为什么把 Payload 放进 Next.jsPayload 本身是一个基于 Node.js 的开源 Headless CMS而 cms-payload 示例 演示的正是官方payloadcms/next-payload包的能力让 Payload 以 API 路由和静态资源的形式运行在 Next.jsPages Router API App Router Admin中从而可以用 Vercel 等边缘/Serverless 平台整体部署无需单独维护一个 Express 服务。从 package.json 可以看到该示例的关键依赖组合payload1.9.2Payload 核心payloadcms/next-payload0.0.27Next.js 集成层提供withPayload配置函数和 API 处理器payloadcms/plugin-cloud-storageaws-sdk/client-s3将媒体文件存入 S3 而非本地磁盘Serverless 环境的关键前提;vercel/edge为运行在 Vercel Edge 环境提供必要的 Node API 垫片。快速开始克隆、安装与本地开发使用 create-next-app 引导示例按照 README 的说明用create-next-app即可拉取本示例npx create-next-app --example cms-payload cms-payload-appyarn create next-app --example cms-payload cms-payload-apppnpm create next-app --example cms-payload cms-payload-app本地开发的软件依赖README 列出的本地开发前置条件MongoDBPayload 的数据库Node NPM / Yarn一个用于存储媒体文件的 S3 Bucket可选。启动步骤克隆仓库或使用create-next-app生成的项目运行yarn或npm install运行cp .env.example .env并按.env.example填写全部环境变量运行yarn dev即next dev启动开发服务器访问http://localhost:3000/admin即可进入 Payload 管理后台。部署到云端如 Vercel时核心要求只有两点一个 Mongo Atlas 数据库连接串以及一个 S3 Bucket可选。把.env.example中的变量替换为真实值即可上线。环境变量全解.env.example 是理解整个集成的心跳逐条说明如下变量用途MONGODB_URIPayload 使用的 MongoDB 连接串如mongodb://localhost/payload-vercel-functionsServerless 部署时填 Mongo Atlas 连接串PAYLOAD_SECRETPayload 的会话签名密钥PAYLOAD_CONFIG_PATHPayload 配置文件路径示例中为dist/payload.config.jsNEXT_PUBLIC_APP_URLNext.js 站点的公开地址默认http://localhost:3000PAYLOAD_PUBLIC_CMS_URLCMS 的公开地址用于内容变更后回调解密再生成接口S3_ACCESS_KEY_ID/S3_SECRET_ACCESS_KEYS3 写权限凭证供媒体上传使用S3_REGIONS3 区域NEXT_PUBLIC_S3_HOSTNAME/NEXT_PUBLIC_S3_BUCKETS3 主机名与 Bucket 名同时用于next/image的远程图片域名白名单PAYLOAD_PRIVATE_REGENERATION_SECRETPayload 侧调用再生成接口时携带的密钥NEXT_PRIVATE_REGENERATION_SECRETNext.js 侧再生成接口校验的密钥注意最后两个变量的分工前者是 Payload 发出的请求凭证后者是 Next.js 接口端用来验签的二者必须一致才能触发按需再生成下文详述。withPayloadNext.js 配置的改造点next.config.js展示了集成层的两个关键动作const { withPayload } require(payloadcms/next-payload); const nextConfig withPayload( { reactStrictMode: true, // 将 /admin 下所有路径回退到 Admin 单页应用入口 rewrites: [{ source: /admin/(.*), destination: /admin/index.html }], images: { remotePatterns: [ { protocol: https, hostname: nextjs-vercel.payloadcms.com, port: , pathname: /my-account/**, }, { protocol: https, hostname: process.env.NEXT_PUBLIC_S3_HOSTNAME, port: , pathname: /${process.env.NEXT_PUBLIC_S3_BUCKET}/**, }, ], }, }, { // 指向 Payload 配置文件 configPath: path.resolve(__dirname, ./payload/payload.config.ts), }, ); module.exports nextConfig;三个值得关注的细节withPayload包装它会在构建时为 Payload Admin 生成静态资源并注入相关 Webpack 规则第二个参数configPath告诉集成层 payload.config.ts 的位置。/admin路由重写Payload Admin 是一个单页应用Next.js 把/admin/*全部指向/admin/index.html由前端路由接管深层路径。remotePatterns白名单媒体图片来自 S3必须把NEXT_PUBLIC_S3_HOSTNAME Bucket 前缀加入next/image的远程域名白名单否则Image组件会拒绝加载 CMS 中的图片。Payload 配置Collection、S3 媒体存储与类型生成payload/payload.config.ts是本示例的 CMS 配置核心import { buildConfig } from payload/config; import { cloudStorage } from payloadcms/plugin-cloud-storage; import { s3Adapter } from payloadcms/plugin-cloud-storage/s3; const adapter s3Adapter({ config: { endpoint: https://${process.env.NEXT_PUBLIC_S3_HOSTNAME}, region: process.env.S3_REGION, forcePathStyle: true, credentials: { accessKeyId: process.env.S3_ACCESS_KEY_ID as string, secretAccessKey: process.env.S3_SECRET_ACCESS_KEY as string, }, }, bucket: process.env.NEXT_PUBLIC_S3_BUCKET as string, }); export default buildConfig({ collections: [Pages, Users, Media], globals: [MainMenu], typescript: { outputFile: path.resolve(__dirname, ../payload-types.ts), }, graphQL: { schemaOutputFile: path.resolve(__dirname, generated-schema.graphql), }, plugins: [ cloudStorage({ collections: { media: { adapter, disablePayloadAccessControl: true, }, }, }), ], });要点解析S3 适配器是 Serverless 化的关键Serverless 平台没有持久本地磁盘媒体文件必须落在对象存储上。这里通过payloadcms/plugin-cloud-storage的s3Adapter接管mediacollection 的文件读写凭证与 Bucket 全部来自环境变量。typescript.outputFilePayload 会在构建/生成时把每个 Collection 的字段类型输出到 payload-types.ts前端组件因此获得完整的类型推导。package.json中的generate:types脚本cross-env PAYLOAD_CONFIG_PATHpayload/payload.config.ts payload generate:types可手动触发该过程。graphQL.schemaOutputFile同时导出一份 GraphQL Schema配合后文的 GraphQL API 路由使用。API 路由Pages Router 承载 Payload 请求Payload 的 REST API 在示例中由 Pages Router 的 API 路由承载。以pages/api/[collection]/index.ts为例import handler from payloadcms/next-payload/dist/handlers/[collection]; export default handler; export const config { api: { bodyParser: false, externalResolver: true, }, };整个pages/api/[collection]/目录是一套极薄的转发层index.ts列表/查询、[id].ts单文档读写、login.ts、logout.ts、me.ts、refresh.ts、first-register.ts、forgot-password.ts、init.ts、access/[id].ts等路由各自一行把请求委托给payloadcms/next-payload打包好的对应 handler。两个config参数值得注意bodyParser: false由 Payload 自行解析请求体因为它需要处理文件上传等复杂 payloadexternalResolver: true允许这些路由以独立解析器方式挂载兼容 Serverless 冷启动场景。此外还有全局与 GraphQL 相关的路由pages/api/globals/[global]/全局设置读写、pages/api/graphql.ts 与pages/api/graphql-playground.tsGraphQL 端点及调试页、pages/api/access.ts权限校验。Admin 界面App Router 中的 Root 组件Admin 面板位于 App Router 的路由组(payload)中。app/(payload)/admin/page.tsx/admin/page.tsx) 只有十几行use client; import React from react; import Root from payload/dist/admin/Root; const PayloadAdmin () { const [mounted, setMounted] React.useState(false); React.useEffect(() { setMounted(true); }, []); if (!mounted) return null; return Root /; }; export default PayloadAdmin;这里用客户端状态确保Root只在浏览器端挂载避免 SSR 时访问window报错。app/(payload)/admin/[...slug]/page.tsx则把/admin下所有深层路径都渲染为同一组件// Need to render the same component for anything within /admin export { default } from ../page;前端路由的深度路径由 Payload Admin 自己处理Next.js 侧只需保证「同一个组件兜底一切子路径」。内容驱动的前端RSC 读取 按需再生成服务端组件直接查询 Payloadapp/(site)/[slug]/page.tsx展示了内容如何流入 Next.jsimport { getPayloadClient } from ../../../payload/payloadClient; const Page async ({ params: { slug } }) { const payload await getPayloadClient(); const pages await payload.find({ collection: pages, where: { slug: { equals: slug || home } }, }); const page pages.docs[0]; if (!page) return notFound(); return ( AdminBar adminBarProps{{ collection: pages, id: page.id }} / Hero {...page.hero} / Blocks blocks{page.layout} / / ); }; export async function generateStaticParams() { const payload await getPayloadClient(); const pages await payload.find({ collection: pages, limit: 0 }); return pages.docs.map(({ slug }) ({ slug })); }页面数据通过getPayloadClient()直连数据库查询生产部署中通常经由 Payload APIgenerateStaticParams在构建时枚举全部页面 slugpublishedOnly访问控制见 payload/access/publishedOnly.ts保证只有已发布的文档可被前端读取。Pages collection 定义了一个「标题 Hero Blocks 布局 Slug」的结构layout字段由CallToAction、Content、MediaBlock三种块组成与components/Blocks/下的 React 组件一一对应——这就是典型的「结构化内容 → 服务端组件」映射。从内容变更到页面再水合的完整链路这是整个示例最有实战价值的部分链路由三端拼合Payload 侧的 afterChange Hookpayload/utilities/regenerateStaticPage.ts挂在 Pages collection 的afterChange钩子上见 Pages.ts 中hooks: { afterChange: [regenerateStaticPage] }。文档变更后它向 Next.js 站点发起请求const res await fetch( ${process.env.PAYLOAD_PUBLIC_CMS_URL}/api/regenerate?secret${process.env.PAYLOAD_PRIVATE_REGENERATION_SECRET}path${path}, );Next.js 侧的再生成接口pages/api/regenerate.ts校验secret与NEXT_PRIVATE_REGENERATION_SECRET是否一致解析出path后调用res.revalidate(path)触发该路径的按需再水合密钥不匹配返回 401缺少 path 返回 400。效果编辑者在http://localhost:3000/admin修改并保存页面后对应静态页面会被立即重新生成无需整站重建。这条「Hook → 带密钥的内部 API 调用 → revalidate」的链路是内容管理与静态生成保持同步的通用模式也解释了.env.example中两个*_REGENERATION_SECRET变量必须配对的原因。构建与运行命令package.json 中的脚本一览脚本说明yarn dev启动next dev开发服务器yarn build/yarn build:next构建生产版本withPayload会在构建中一并产出 Admin 资源yarn start启动生产服务器yarn install:payload执行next-payload install初始化 Payload 集成所需的构建钩子yarn generate:types生成payload-types.ts类型定义yarn generate:graphQLSchema导出 GraphQL Schema 文件小结这个示例给出的是一套边界清晰的最小可行方案用withPayload改造 Next.js 配置Pages Router 转发 Payload REST APIApp Router 挂载 Admin 单页应用S3 承载媒体存储afterChangeHook revalidate打通内容同步。所有关键文件集中在 examples/cms-payload 目录下按「next.config.js→pages/api/→app/(payload)/→payload/」的顺序阅读源码即可完整还原其实现脉络。若你的项目需要更丰富的第三方 CMS 集成参考同仓库还有 cms-prismic、cms-contentful、cms-wordpress 等示例可对照阅读。【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考