Decap CMS:把 Git 仓库变成静态站点的内容后台
Decap CMS(原 Netlify CMS)的定位是:把一个单页 React 应用(SPA)放进网站 /admin/ 路径。编辑者在 CMS 中填写表单,内容仍以 Markdown、JSON、YAML 或 TOML 文件保存在 Git 仓库,再由静态站点生成器构建公开站点。本文依据 2b772c7 对应的源码快照整理。[E01][E02]
选型结论:已经把内容放在 Git 中、又希望非开发人员拥有可配置编辑后台的团队,可以优先评估 Decap CMS;提交、分支和 Pull Request 审阅仍能保留。需要数据库查询、复杂权限模型、实时协作或完全托管内容平台时,应把 Decap CMS 与托管型或无头 CMS(SaaS/headless CMS,内容通过服务商 API 提供)放在一起比较。
后文的“后端”指负责读写 Git 内容的适配器,“内容集合”对应配置文件中的 collection,“编辑工作流”指用草稿分支和 Pull Request 审阅内容的方式。
先判断是否适合
- Decap CMS 解决什么问题:给静态站点增加内容编辑界面,而不要求编辑者直接改 Markdown 或 Git 文件。[E01]
- 内容放在哪里:后端 API 负责读写 Git 仓库;
config.yml决定文件格式、目录和媒体位置。换句话说,内容仍是普通 Git 文件,后台只是提供编辑界面。[E03][E05] - 扩展方式:主应用用扩展注册表登记后端、字段组件、编辑器组件和语言包。仓库内置 GitHub、GitLab、Bitbucket 等多种后端,增加新字段时只需接入对应组件。[E04]
- 工程形态:
packages/*组成一个超过 20 个包的多包单仓库(monorepo),维护者用 npm workspaces 管理依赖;批量构建和发布由仓库脚本负责。[E06][E07]
适合谁,不适合谁
适合
- 使用 Hugo、Jekyll、Gatsby、Next.js 静态导出或其他静态生成器的网站;
- 希望内容修改留下 Git commit、分支和 Pull Request 记录的团队;
- 需要通过 YAML 配置内容模型,并允许逐步加入自定义字段组件、预览和媒体库的项目;
- 能接受“Git 是事实来源,构建系统负责发布”的运维边界。
不适合或需要谨慎
- 需要基于角色的细粒度访问控制(RBAC)、审计报表、实时协作、事务查询或大量结构化关系数据的内容平台;
- 不希望编辑者接触 Git 权限、OAuth 授权登录、Git Gateway 或仓库分支策略的团队;
- 依赖某个后端的商业服务,却没有准备好处理 OAuth 授权、API 速率限制、媒体存储和失败重试;
- 需要在文章未覆盖的部署环境直接执行生产迁移,应该先在目标站点完成小范围验证。
项目快照
| 项目版本 | decap-cms@3.15.1(截至 2026 年 8 月 30 日的最新版本发布) |
|---|---|
| 源码快照 | 2b772c7(main HEAD) |
| 项目类型 | React 单页应用 + 可扩展 CMS 框架 |
| 主要语言 | JavaScript、TypeScript、HTML、CSS |
| 许可证 | MIT(仓库 LICENSE 与 GitHub metadata 均标注) |
| 社区信号 | 约 1.93 万 Star、3.1 千个派生仓库、592 个开放 Issue;仅作活跃度背景,不等于质量评分 |
| 核对日期 | 2026 年 8 月 30 日 |
| 验证边界 | 源码/清单静态核对;未安装、未运行、未登录 GitHub/Netlify |
社区指标和版本发布记录会变化,应以 GitHub 仓库及 Releases 当前页面为准。[E08][E09]
源码里的三处分工
1. CMS 嵌入站点,不另起内容服务器
根 README 将 Decap CMS 描述为放入站点 /admin 部分的单页应用。未设置 window.CMS_MANUAL_INIT 时,decap-cms 入口会自动调用 CMS.init()。入口还会把 CMS、初始化函数以及兼容用的 createClass、h 暴露到 window。快速安装只需要 HTML 和配置文件;需要自定义扩展时,再通过 npm 组合所需模块。[E01][E10]
2. 扩展集中登记,再由统一入口装配
packages/decap-cms-app/src/extensions.js 集中登记后端适配器、字段组件、编辑器组件和语言包。扩展注册表把核心编辑器与后端、字段、媒体能力分开:新增后端通常实现统一接口,新增字段只需登记组件,不必改动所有编辑页面。[E04]
3. GitHub 后端同时覆盖两种 API 和编辑工作流
GitHub 后端把认证、文件读写和审核协作拆开维护。实现层读取分支、开放式贡献、use_graphql 和媒体目录等配置,再根据配置选择对应的 API 客户端。[E11][E12]
文件读写同时提供 REST 风格接口和 GraphQL 查询接口。前者处理文件、目录树、提交和 Pull Request,后者借助 Apollo 客户端库读取仓库文件和 Pull Request。fragment 是 GraphQL 查询中复用字段的片段,作用是保持返回结构一致。[E11][E13]
普通编辑、开放式贡献和编辑工作流共用同一套编辑模型,但权限、分支策略和 API 差异仍要纳入部署设计。源码把底层失败统一转换成 CMS 可识别的 API 错误,方便界面展示和后续处理。[E12][E13]
典型使用任务
把 CMS 放进 /admin/
内容分发网络(CDN)安装适合先验证流程:在站点中加入 CMS HTML 入口和 config.yml,再配置一个可用后端。项目 README 同时提供单个 HTML 文件的快速安装和 npm 包安装路径。[E01]
<script src="https://unpkg.com/decap-cms@3.15.1/dist/decap-cms.js"></script>上面的版本固定方式只是示例。生产环境应根据官方安装文档和发布策略选择版本,并验证内容分发网络、内容安全策略(CSP)与浏览器兼容性。
配置第一组内容集合
以下是官方配置模型的最小示例。backend 指定内容读写方式,media_folder 和 public_folder 分别指定媒体存储目录与公开 URL,collections 描述内容集合;目录、字段和发布模式需要按实际静态站点调整。[E05][E14]
backend:
name: github
repo: owner/site-content
branch: main
media_folder: static/images/uploads
public_folder: /images/uploads
collections:
- name: posts
label: Posts
folder: content/posts
create: true
fields:
- { label: Title, name: title, widget: string }
- { label: Date, name: date, widget: datetime }
- { label: Body, name: body, widget: markdown }核心包的配置规则还覆盖本地后端、多语言、媒体处理、发布模式、预览链接和内容集合视图。首版配置不必一次启用全部选项,先确认后端与内容目录能够完成最短流程。[E05]
启用草稿与 Pull Request 审核
将 publish_mode 设为 editorial_workflow 后,CMS 会围绕草稿分支和 Pull Request 组织编辑流程。GitHub 后端还支持 open_authoring,允许贡献者从派生仓库(fork)发起改动。权限范围(OAuth scope)决定令牌能访问什么,分支保护和合并策略也必须一起配置,不能只改 YAML 就视为完成上线。[E12][E15]
从接入到首次发布
- 准备一个已能正常构建的静态站点,并确认内容目录、媒体目录和部署触发方式。
- 选择安装方式:快速路径使用内容分发网络(CDN)HTML;需要自定义构建产物、扩展或依赖约束时使用 npm 包。[E01][E10]
- 创建
admin/index.html和admin/config.yml,先只配置一个内容集合、一个文本字段和一个 Markdown 字段。 - 选择后端适配器。GitHub 后端需要仓库、分支和认证方式;使用 Git Gateway 时,Netlify Identity 负责身份认证,Git Gateway 负责把请求代理到 Git 内容后端,也可以换成兼容的代理服务。[E11][E16]
- 在隔离的测试仓库中完成登录、读取文章、保存草稿、生成提交和 PR、构建静态站点,再演练一次回滚。
- 再增加媒体处理、多语言、自定义字段组件、预览和开放式贡献。每增加一项后端能力,都记录权限、失败分支和恢复方式。
成功标准不是“看到 /admin/ 页面”,而是编辑者能在预期权限下完成一次可追溯的内容变更,静态站点也能产出可观察、可回滚的构建结果。
源码如何协作:沿调用链看运行过程
上节概括了模块职责,本节沿启动和保存两条调用链,说明这些模块如何在一次编辑操作中配合。
启动链路
decap-cms-core/src/bootstrap.js 创建 React 根节点,挂载 Redux 状态容器、路由和错误边界。源码中的 Provider、Router 分别负责向组件提供状态和路由上下文。启动过程先分发 loadConfig,回调中再分发 authenticateUser,所以配置加载和用户认证是进入编辑界面前的两个关键门。[E17]
模块如何分工
一次保存操作的源码路径
一次保存操作可以拆成四步:表单收集内容,入口逻辑按内容集合选择后端,序列化内容和媒体,最后提交到 Git。源码入口位于 core/src/actions/entries.ts,这里的 action 指负责协调一次状态变化的函数。[E18]
GitHub 后端的 API.ts 负责 REST 文件、目录树、提交和 Pull Request;GraphQLAPI.ts 负责查询仓库文件和 Pull Request。两条客户端路径共同支撑保存和审核,但没有覆盖所有字段组件、多语言和媒体分支。[E12][E13]
文件结构与源码阅读顺序
packages/
├── decap-cms-app/ # 面向使用者的入口与默认扩展装配
├── decap-cms-core/ # 启动、Redux、路由、编辑器、配置和 actions
├── decap-cms-backend-github/ # GitHub REST/GraphQL backend
├── decap-cms-backend-git-gateway/ # Netlify Git Gateway 与 JWT/PKCE 认证
├── decap-cms-backend-*/ # GitLab、Bitbucket、Gitea、Forgejo、Azure 等
├── decap-cms-lib-auth/ # OAuth/PKCE 辅助
├── decap-cms-lib-util/ # API、媒体、文件和 workflow 公共工具
└── decap-cms-widget-*/ # 字段 widget
cypress/ # backend、workflow、media 和 widget E2E 场景
dev-test/ # 多 backend 本地测试页面与配置源码阅读可以按“入口装配 → 启动流程 → 保存操作 → 后端请求”的顺序进行。先看扩展注册,再看配置加载和认证,随后追踪一次内容保存,最后进入 GitHub API 客户端。对应文件依次是 extensions.js、bootstrap.js、entries.ts、API.ts 和 GraphQLAPI.ts。Cypress 测试用例用于核对边界场景。[E04][E17][E18][E19]
工程化与质量信号
根 package.json 提供代码规范检查、TypeScript 类型检查、Jest 单元测试和 Cypress 端到端测试命令。持续集成流程会把这些检查组合起来。仓库还按后端适配器、编辑工作流、媒体库和字段组件维护 Cypress 场景,兼容性测试因此成为维护成本的重要部分。[E06][E19]
这套设计也增加维护负担。这是一个规模不小的前端多包单仓库,构建、状态管理、GraphQL、测试和编辑器各自依赖不同工具。升级或自定义时,维护者需要同时处理包版本、构建流程、依赖约束、后端 API 和站点部署。Decap CMS 不是只改几行 YAML 的插件。[E06][E20]
安全、运维和限制
- 认证与权限:GitHub 后端会使用 OAuth 授权令牌;
auth_scope、仓库权限、分支和开放式贡献设置共同决定可读写范围。[E12] - 第三方服务边界:Git Gateway 依赖 Netlify Identity(Netlify 的身份认证服务),并使用 JWT(令牌格式)和 PKCE(授权码保护流程),还可接入大文件服务;这条链路不能直接替代 GitHub 后端。[E16]
- 内容与媒体:媒体文件可能走 Git 大文件存储(LFS)、外部媒体库或浏览器端图片处理;存储成本、处理结果和回滚路径需要分别确认。[E05][E16]
- 失败恢复:API 限流、OAuth 过期、分支冲突、Pull Request 合并失败和构建失败都应在测试仓库中演练。
- 供应链:生产站点应锁定 npm/CDN 版本、配置内容安全策略(CSP)、审查自定义字段组件和媒体库,并在升级前阅读变更记录与发布说明。
- 许可证:Decap CMS 仓库使用 MIT,但 Git 服务、媒体服务、OAuth 应用和站点内容的条款需要分别核对。
和哪些项目比较
| 选择 | 更适合的场景 | 关键取舍 |
|---|---|---|
| Decap CMS | Git 内容源、静态生成器、需要 PR/分支工作流 | 灵活且可自托管前端,但认证和 Git 运维由团队承担 |
| TinaCMS | 希望更强的可视化编辑和 React 集成 | 编辑体验更强,平台和数据模型取舍不同 |
| Sanity / Contentful | 需要托管 API、结构化查询、团队权限 | 降低 Git 运维,但引入 SaaS、费用和平台依赖 |
| Directus / Strapi | 希望自建数据库型 headless CMS | 数据库与 API 能力更强,部署和运维面更大 |
比较时优先看内容事实来源、认证责任、预览/发布方式、媒体存储、审计和迁移成本,不要只比较编辑器截图。
上线前要验证的 5 件事
- 用测试仓库验证 GitHub REST 后端的登录、读取、写入、冲突和回滚。
- 如果需要编辑工作流,再验证分支保护、PR 状态同步和开放式贡献的派生仓库流程。
- 用目标静态站点验证
media_folder、public_folder、Git 大文件存储(LFS)、外部媒体和构建缓存。 - 在隔离环境中运行仓库声明的
npm ci、npm run test:ci和必要的端到端测试(E2E)。 - 将实际验证结果补回证据记录,并明确区分源码静态核对与运行验证。
当 main 指向新的提交、发布新版本或后端 API 变化时,应重新审核文章,避免沿用旧结论。[E08][E21]
证据索引
E01:仓库 README,项目定位、SPA/admin/、安装方式和 MIT 声明。E02:仓库 main HEAD commit,文章采用的源码快照。E03:GitHub backend README,Implementation/API/GraphQLAPI/AuthenticationPage 分工。E04:decap-cms-app/src/extensions.js,后端、widget、编辑器组件和 locale 注册。E05:decap-cms-core/src/constants/configSchema.js,backend、media、i18n、publish mode 和 collection 配置 schema。E06:根package.json,Nx/Lerna monorepo、build/test/lint/type-check 命令和 workspaces。E07:packages/decap-cms-core/README.md,超过 20 个包的 monorepo 说明。E08:GitHub REST repository metadata,默认分支、语言、topics、许可证和动态指标。E09:GitHub latest release API,decap-cms@3.15.1。E10:packages/decap-cms-app/src/index.js与 package README,自动/手动初始化及 npm/CDN 使用方式。E11:packages/decap-cms-backend-github/package.json和 README,REST/GraphQL 依赖与模块结构。E12:packages/decap-cms-backend-github/src/implementation.tsx,branch、open authoring、API root、media 和 GraphQL 配置。E13:packages/decap-cms-backend-github/src/GraphQLAPI.ts,Apollo、repository/blob/Pull Request 查询和错误处理。E14:Decap CMS 官方 configuration options 文档,配置入口和选项说明。E15:仓库 Cypress editorial workflow specs,REST/GraphQL/open authoring 测试覆盖。E16:packages/decap-cms-backend-git-gateway/README.md与 implementation,Netlify Identity、Git Gateway、JWT/PKCE 和 Large Media。E17:packages/decap-cms-core/src/bootstrap.js,React root、Redux、Router、loadConfig 和 authenticateUser 启动链。E18:packages/decap-cms-core/src/actions/entries.ts,entry provider 选择和持久化 action。E19:仓库 Cypress 目录和根测试脚本,backend/workflow/media/widget E2E 与 unit test。E20:packages/decap-cms-core/package.json,React/Redux/Immutable/webpack 等核心依赖。E21:文章采用 GitHub Guides refresh policy,commit 变化进入 review-due,不自动判定 stale。