后端【免费下载链接】keystoneThe superpowered headless CMS for Node.js — built with GraphQL and React项目地址https://gitcode.com/gh_mirrors/key/keystone点击查看免费下载导读examples/framework-nextjs-two-servers是 Keystone基于 GraphQL 与 React 构建的 Node.js 无头 CMS官方仓库中一个极具实战价值的参考实现它将Keystone 后端服务GraphQL API Admin UI与Next.js 前端服务页面渲染拆分为两个独立进程、两个独立端口运行。读完本文你将掌握这种双服务器架构的目录组织方式、一条命令并行启动两端的做法以及 Next.js 前端如何通过 GraphQL 客户端消费 Keystone API、如何渲染 Keystone 文档字段Document Field内容为在真实项目中分离 CMS 后端与站点前端提供可直接复用的模板。一、架构总览为什么要把 Keystone 与 Next.js 拆成两个服务在单仓库monorepo内Keystone 官方提供了多种与 Next.js 集成的模式例如 App Router / Pages Router 的目录内集成以及framework-nextjs-two-servers所演示的双服务器模式。后者把系统切分为两个相互独立、可各自启动与扩展的服务服务职责默认端口关键技术keystone-server数据模型lists、GraphQL API、Admin UI、种子数据3000keystone-6/core、keystone-6/fields-document、Prisma SQLitenextjs-frontend面向用户的页面渲染、静态生成SSG8000Next.jsPages Router、keystone-6/document-renderer这种拆分带来的直接收益是后端 CMS 与前端站点可以独立开发、独立部署、独立扩容前端构建/发布不需要重启后端后端的 Admin UI 与 GraphQL API 也不会受前端页面代码影响。整个示例的目录结构如下相对仓库根目录examples/framework-nextjs-two-servers/ ├── package.json # 根脚本并行启动两个子服务 ├── keystone-server/ # Keystone 后端 API 服务 │ ├── keystone.ts # Keystone 配置入口 │ ├── prisma.config.ts # Prisma 配置 │ ├── schema.prisma / schema.graphql# 生成的数据库与 GraphQL schema │ └── src/ │ ├── schema.ts # listsUser / Post定义 │ └── seed/ # 种子数据脚本与 JSON └── nextjs-frontend/ # Next.js 前端服务 ├── next.config.js └── src/ ├── graphql.ts # 轻量 GraphQL 客户端 └── pages/ ├── index.tsx # 首页文章列表 └── blog/[slug].tsx # 文章详情页二、运行示例一条命令并行启动两个服务1. 安装依赖原文档要求先在仓库根目录安装依赖。本仓库使用 pnpm 工作区根目录存在pnpm-workspace.yaml与pnpm-lock.yaml因此pnpm install该命令会通过 workspace 依赖如keystone-6/core: workspace:^、keystone-6/document-renderer: workspace:^把核心包与示例内部依赖一并解析安装。2. 启动 Keystone 与 Next.js 两个服务从仓库根目录进入示例目录并启动cd examples/framework-nextjs-two-servers pnpm dev此时会发生两件事GraphQL 服务器与 Admin UI启动在http://localhost:3000/api/graphql为 GraphQL 端点Admin UI 可管理数据Next.js 服务器启动首页服务在http://localhost:8000。之所以一条命令能同时拉起两个进程关键在于根目录package.json的 dev 脚本使用了 pnpm 的并行过滤执行{ name: keystone-6/monorepo-example-framework-nextjs-two-servers, scripts: { dev: pnpm --parallel --filter ./keystone-server --filter ./nextjs-frontend dev } }--parallel让两个子包的dev脚本并行运行--filter ./keystone-server与--filter ./nextjs-frontend分别指向两个子目录。3. 备选方式两个终端分别启动原文档也提供了更贴近生产习惯的替代方式打开两个终端分别进入examples/framework-nextjs-two-servers/keystone-server与examples/framework-nextjs-two-servers/nextjs-frontend各自执行pnpm dev。这样两个服务的日志互不干扰便于单独调试后端 API 或前端页面。三、Keystone 后端服务keystone-server详解1. 启动脚本与种子数据钩子keystone-server/package.json中的脚本展示了 Keystone 开发/构建/启动的完整生命周期{ scripts: { dev: keystone dev --seed-database, start: keystone start --seed-database, build: keystone build, check: keystone postinstall } }注意dev与start都携带了--seed-database参数它与 keystone.ts 中的onConnect钩子配合只有命令行参数包含--seed-database时才会执行seedDatabase(context)写入种子数据。这意味着你可以通过去掉该参数来启动一个不灌数据的干净环境。2. 数据库配置SQLite Better SQLite3 驱动keystone.ts 中数据库使用sqliteprovider并通过prisma/adapter-better-sqlite3提供驱动适配const db: KeystoneConfigPreTypeInfo[db] { provider: sqlite, prismaClientOptions: () ({ adapter: new PrismaBetterSqlite3({ url: process.env.DATABASE_URL || file:./database.db }), }), async onConnect(context: Context) { if (process.argv.includes(--seed-database)) { await seedDatabase(context) } }, } export default config({ db, lists })要点数据库文件路径通过环境变量DATABASE_URL覆盖默认回退到file:./database.dbprisma.config.ts 中同样读取DATABASE_URL默认file:./database.db并指定 schema 文件schema.prisma与migrations目录保证 CLI 与运行时配置一致生成的schema.prisma与schema.graphql就位于keystone-server目录下可直接查看 Keystone 根据 lists 生成的数据层与 API 层产物。3. 数据模型User 与 Postsrc/schema.ts 定义了本示例的两张核心表展示了文本、时间戳、文档与关系字段的常见组合export const lists { User: list({ access: allowAll, fields: { email: text({ validation: { isRequired: true }, isIndexed: unique }), name: text({ validation: { isRequired: true } }), posts: relationship({ ref: Post.author, many: true }), }, }), Post: list({ access: allowAll, fields: { title: text({ validation: { isRequired: true } }), slug: text({ isIndexed: unique, validation: { isRequired: true } }), content: document({ formatting: true, dividers: true, links: true, layouts: [ [1, 1], [1, 1, 1], ], }), publishDate: timestamp({ defaultValue: { kind: now } }), author: relationship({ ref: User.posts, many: false }), }, }), } satisfies Lists值得注意的配置项email与slug都设置了isIndexed: unique是按唯一标识查询如博客页按 slug 取文章的索引基础content是来自keystone-6/fields-document的文档字段开启了formatting富文本格式、dividers分割线、links链接以及两种网格布局[1,1]与[1,1,1]publishDate使用timestamp({ defaultValue: { kind: now } })新记录创建时自动填入当前时间User.posts与Post.author互为反向关系ref: Post.author/ref: User.posts是一对多的双向关联。4. 种子数据脚本幂等写入src/seed/index.ts 实现了可重复执行的种子逻辑读取users.json与posts.json先按email/slug查询数据库中已存在的记录只createMany新增部分其中帖子内容取自 JSON 里的content.document与 Keystone 文档字段的存储结构一致。整个过程通过context.sudo()获取特权上下文绕过权限限制执行写入并在控制台输出 Seeding database...与完成日志。四、Next.js 前端服务nextjs-frontend详解1. 独立端口与配置nextjs-frontend/package.json的脚本明确了前端跑在 8000 端口{ scripts: { dev: next dev --port 8000, build: next build, export: next build next export, start: next start --port 8000 } }next.config.js 中开启了experimental.externalDir因为在 Keystone monorepo 内部引用外部目录的依赖文件内注释也明确说明如果你不在 Keystone 仓库内部开发就不需要这个配置。2. 轻量 GraphQL 客户端src/graphql.ts 是整个前后端通信的关键桥梁const API_URI process.env.API_URI || http://localhost:3000/api/graphql export const gql ([content]: TemplateStringsArray) content export async function fetchGraphQL(query: string, variables?: Recordstring, any) { return fetch(API_URI, { method: POST, body: JSON.stringify({ query, variables }), headers: { Content-Type: application/json }, }) .then(x x.json()) .then(({ data, errors }) { if (errors) { throw new Error(GraphQL errors occurred:\n${errors.map((x: any) x.message).join(\n)}) } return data }) }它默认把 GraphQL 请求指向http://localhost:3000/api/graphql即 Keystone 后端并支持通过环境变量API_URI覆盖——生产环境下可以把 API_URI 指向真实部署的后端域名。函数会在响应包含errors时抛出包含全部错误信息的异常便于前端页面捕获并展示。3. 首页静态生成文章列表src/pages/index.tsx 使用 Next.js 的getStaticProps在构建期向 Keystone 发起posts查询拉取id / title / slug / publishDate / author.name然后渲染为文章链接列表并附带PublishDate、AuthorInfo两个小组件展示发布时间与作者查询失败时页面会展示错误信息而不是直接崩溃。4. 文章详情页getStaticPaths DocumentRenderersrc/pages/blog/[slug].tsx 演示了博客站最常见的数据获取组合getStaticPaths先查询全部文章的slug生成静态路径列表fallback: falsegetStaticProps再按slug查询单篇文章包含content { document }文档字段内容页面主体使用keystone-6/document-renderer的DocumentRenderer组件把 Keystone 文档字段的 JSON 结构渲染为 React 元素DocumentRenderer document{post.content.document} /这正是双服务器模式下前端渲染 CMS 富文本内容的官方推荐方式后端存结构化文档 JSON前端用专用渲染器输出页面不依赖后端的 HTML。五、双服务器的通信链路与部署要点综合两端源码可以梳理出完整的数据流从源码结构可以推断开发者在localhost:3000的 Admin UI 中维护User/Post数据构建或运行nextjs-frontend时src/graphql.ts的fetchGraphQL向localhost:3000/api/graphql发起 POST 请求Keystone 根据src/schema.ts定义的 lists 与生成在keystone-server目录下的schema.graphql处理查询返回 JSONNext.js 页面在构建期getStaticProps/getStaticPaths取得数据并生成静态页面文档字段再由DocumentRenderer渲染。部署与运行层面需要注意端口约定Keystone 固定 3000GraphQL 端点3000/api/graphqlNext.js 固定 8000修改端口时需同步调整API_URI或--port参数环境变量数据库地址用DATABASE_URL控制默认file:./database.dbGraphQL 端点用API_URI控制默认http://localhost:3000/api/graphql种子数据keystone dev/start是否灌入种子数据取决于是否携带--seed-database参数种子逻辑本身是幂等的可安全重复执行单仓库前提next.config.js的externalDir仅为在 Keystone monorepo 内运行所需独立项目无需保留。六、小结examples/framework-nextjs-two-servers用最精简的代码量展示了 Keystone 官方支持的一种生产级部署形态Keystone 作为纯后端 API Admin UINext.js 作为独立前端。通过根目录一行pnpm dev或两个终端分别启动即可并行运行前后端通过http://localhost:3000/api/graphql通信前端在构建期完成 SSG 数据获取并用keystone-6/document-renderer渲染文档字段。对于希望将 CMS 数据层与站点渲染层彻底解耦的团队这份示例是理想的起点模板。相关文件快速索引均相对仓库根目录示例总览examples/framework-nextjs-two-servers/README.md双服务并行启动脚本examples/framework-nextjs-two-servers/package.jsonKeystone 配置入口examples/framework-nextjs-two-servers/keystone-server/keystone.ts数据模型定义examples/framework-nextjs-two-servers/keystone-server/src/schema.ts种子数据脚本examples/framework-nextjs-two-servers/keystone-server/src/seed/index.ts前端 GraphQL 客户端examples/framework-nextjs-two-servers/nextjs-frontend/src/graphql.ts首页与文章页index.tsx、blog/[slug].tsx赞分享后端【免费下载链接】keystoneThe superpowered headless CMS for Node.js — built with GraphQL and React项目地址https://gitcode.com/gh_mirrors/key/keystone点击查看免费下载相关推荐在生成式 AI 应用中集成函数调用Function Callinggenerative-ai-for-beginners 第 11 课实战精讲在生成式 AI 应用中集成函数调用Function Callinggenerative ai for beginners 第 11 课实战精讲 本篇技术指后端Next.js FastAPI 双服务架构实战基于 Vercel Services 的前后端分离部署指南Next.js FastAPI 双服务架构实战基于 Vercel Services 的前后端分离部署指南 导读 本指南围绕仓库中的 services/ne示例工程前端后端Keystone 管理后台前端客户端架构解析React Redux 的 Admin UI 双 Bundle 设计Keystone 管理后台前端客户端架构解析React Redux 的 Admin UI 双 Bundle 设计 导读 本文以 admin/client/后端上一篇如何用 React DataSheet 实现 Excel 级别的表格体验终极指南下一篇RamaLama命令行自动补全提升开发效率的小技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
