Astro 博客集成 Decap CMS 完整指南

发表于 2026-01-22 18:00 1286 字 7 min read

吕小布 avatar

吕小布

The first step is to establish that something is possible; then probability will occur.

暂无目录
详细介绍如何为 Astro 静态博客集成 Decap CMS,实现在线编辑和发布文章,告别手动编辑 Markdown 文件的繁琐流程。

本文记录了我为 Astro 博客集成 Decap CMS 的完整过程,包括遇到的问题和解决方案。

什么是 Decap CMS

Decap CMS(原 Netlify CMS)是一个开源的内容管理系统,专为静态网站设计。它的特点是:

  • 基于 Git:内容存储在 GitHub 仓库,不需要数据库
  • Web 编辑器:在浏览器中直接编辑文章
  • 自动提交:发布时自动提交到 GitHub
  • 免费开源:完全免费使用

为什么需要 CMS

之前写博客的流程是:

打开 VS Code → 创建 MD 文件 → 手写 frontmatter → 写正文 → git add/commit/push → 等待构建

这个流程有几个痛点:

  1. 需要打开编辑器
  2. 需要手动写 YAML 格式的 frontmatter
  3. 需要手动执行 git 命令
  4. 不能随时随地写文章

集成 Decap CMS 后:

打开网页 → 填表单 → 写正文 → 点击发布 → 完成

集成步骤

第 1 步:创建配置文件

public/admin/ 目录下创建两个文件:

config.yml

backend:
  name: github
  repo: 你的用户名/你的仓库名
  branch: main
  base_url: https://你的域名
  auth_endpoint: api/auth

media_folder: "public/img"
public_folder: "/img"

# 开启编辑工作流
publish_mode: editorial_workflow

# 中文界面
locale: "zh_Hans"

collections:
  - name: "life"
    label: "生活随笔"
    folder: "src/content/blog/life"
    create: true
    delete: true
    slug: "{{slug}}"
    fields:
      - { label: "标题", name: "title", widget: "string", required: true }
      - { label: "链接", name: "link", widget: "string", required: true }
      - { label: "日期", name: "date", widget: "datetime", required: true }
      - { label: "分类", name: "categories", widget: "list", required: false }
      - { label: "标签", name: "tags", widget: "list", required: false }
      - { label: "描述", name: "description", widget: "text", required: false }
      - { label: "封面", name: "cover", widget: "image", required: false }
      - { label: "草稿", name: "draft", widget: "boolean", default: false }
      - { label: "正文", name: "body", widget: "markdown", required: true }

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>博客编辑器</title>
  </head>
  <body>
    <script src="https://unpkg.com/decap-cms@^3.0.0/dist/decap-cms.js"></script>
  </body>
</html>

第 2 步:创建 OAuth 认证 API

Decap CMS 需要通过 GitHub OAuth 来获取权限。在 src/pages/api/auth/ 目录下创建两个文件:

index.ts(认证入口):

import type { APIRoute } from 'astro';

const GITHUB_CLIENT_ID = import.meta.env.GITHUB_CLIENT_ID;

export const GET: APIRoute = async ({ redirect }) => {
  const authUrl = new URL('https://github.com/login/oauth/authorize');
  authUrl.searchParams.set('client_id', GITHUB_CLIENT_ID);
  authUrl.searchParams.set('scope', 'repo,user');

  return redirect(authUrl.toString());
};

export const prerender = false;

callback.ts(认证回调):

import type { APIRoute } from 'astro';

const GITHUB_CLIENT_ID = import.meta.env.GITHUB_CLIENT_ID;
const GITHUB_CLIENT_SECRET = import.meta.env.GITHUB_CLIENT_SECRET;

export const prerender = false;

export const GET: APIRoute = async ({ url }) => {
  const code = url.searchParams.get('code');

  if (!code) {
    return new Response('Missing code parameter', { status: 400 });
  }

  try {
    const tokenResponse = await fetch('https://github.com/login/oauth/access_token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
      },
      body: JSON.stringify({
        client_id: GITHUB_CLIENT_ID,
        client_secret: GITHUB_CLIENT_SECRET,
        code,
      }),
    });

    const tokenData = await tokenResponse.json();

    if (tokenData.error) {
      return new Response(`OAuth error: ${tokenData.error_description}`, { status: 400 });
    }

    const { access_token } = tokenData;

    const html = `
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>认证成功</title>
    <script>
      (function() {
        function receiveMessage(e) {
          window.opener.postMessage(
            'authorization:github:success:{"token":"${access_token}","provider":"github"}',
            e.origin
          );
        }
        window.addEventListener("message", receiveMessage, false);
        window.opener.postMessage("authorizing:github", "*");
      })();
    </script>
  </head>
  <body>
    <p>认证成功,正在完成登录...</p>
  </body>
</html>
    `;

    return new Response(html, {
      headers: { 'Content-Type': 'text/html' },
    });
  } catch (error) {
    return new Response('Authentication failed', { status: 500 });
  }
};

第 3 步:配置 Astro

astro.config.mjs 中添加 Vercel 适配器:

import vercel from '@astrojs/vercel';

export default defineConfig({
  output: 'static',
  adapter: vercel(),
  // ... 其他配置
});

安装依赖:

pnpm add @astrojs/vercel

第 4 步:创建 GitHub OAuth 应用

  1. 打开 https://github.com/settings/developers
  2. 点击 “New OAuth App”
  3. 填写信息:
    • Application name: MyBlog CMS
    • Homepage URL: https://你的域名
    • Authorization callback URL: https://你的域名/api/auth/callback
  4. 点击 “Register application”
  5. 复制 Client ID 和生成 Client Secret

第 5 步:配置 Vercel 环境变量

在 Vercel 项目设置中添加环境变量:

NameValue
GITHUB_CLIENT_ID你的 Client ID
GITHUB_CLIENT_SECRET你的 Client Secret

第 6 步:部署

git add .
git commit -m "feat: 集成 Decap CMS"
git push

Vercel 会自动构建和部署。

遇到的问题和解决方案

问题 1:页面白屏

原因index.html 中的 <body> 标签为空

解决:把 <script> 标签放到 <body> 里面

问题 2:Vercel 部署失败

错误EISDIR: illegal operation on a directory

原因api/auth/index.tsapi/auth/callback.ts 目录结构冲突

解决:确保 API 路由文件都在 api/auth/ 目录下,并添加 export const prerender = false

问题 3:登录后没反应

原因:OAuth 回调窗口和主窗口之间的消息传递失败

解决:使用 Decap CMS 标准的消息传递方式,先发送 authorizing:github,再监听消息回复

最终效果

集成完成后,访问 https://你的域名/admin/index.html 即可:

  1. 点击 “Login with GitHub” 登录
  2. 选择分类,点击 “New” 创建新文章
  3. 填写表单,编辑内容
  4. 点击 “Publish” 发布

文章会自动提交到 GitHub,Vercel 自动构建,博客自动更新。

可用功能

功能说明
创建文章在线创建新文章
编辑文章修改已有文章
删除文章删除不需要的文章
上传图片拖拽上传图片
草稿功能保存草稿,稍后发布
中文界面界面显示中文

总结

Decap CMS 虽然界面不够美观,但功能够用,最重要的是:

  • 免费:不需要付费
  • 无数据库:内容存在 GitHub
  • 自动化:发布自动触发构建
  • 随时随地:只要有浏览器就能写文章

如果你也在用 Astro 搭建博客,推荐试试 Decap CMS!

© 2024 - 2026 吕小布 @insist
Powered by theme astro-koharu · Inspired by Shoka