赛林格

Astro 使用 Keystatic CMS 无头后端 - 实战演练

🎉 本文分享了博主给 Astro 添加 Keystatic CMS 无头后端的实战操作,包括相应代码编辑,Github “通行证”申请,Cloudflare 部署,以及遇到的相关问题,坑点等等,都进行了详尽的记录。

最近博主一直在折腾 Astro 的无头后端,之前尝试了 Decap CMS , 因为界面和预览都比较丑,所以决定换一个 CMS,网上找了一圈,感觉 Keystatic 似乎还可以,那么这次就来试试它吧。

1. Keystatic 是什么?

Keystatic 是一款通过现代可视化界面管理本地文件的 Git-based 无头 CMS,它将 Notion 般的富文本编辑体验(也支持 mardown),直接嫁接在你的代码仓库之上,无需配置数据库,就能通过自动化的 Git 提交来实现“内容即代码”的类型安全管理与无缝协作。

它是如何运作的?

不同于传统 CMS 需要通过 API 调取远程数据库,Keystatic 的逻辑非常“直脑筋”:

  • 开发环境下: 它直接读取电脑磁盘上的文件。在网页界面点“保存”,它就直接修改你硬盘上的 .md.json
  • 生产环境下: 它通过 GitHub API 与你的仓库通信。你在管理后台点“发布”,它会自动帮你完成一次 Git Commit 或发起一个 Pull Request

Github 1.9K Star 地址:https://github.com/thinkmill/keystatic

2. 本地测试

首先在本地进行测试,安装比较简单,直接在 astro 项目中,输入以下代码进行安装:

npm install @keystatic/core @keystatic/astro
如果你用 pnpm,就改成 pnpm

然后配置 keystatic.config.ts文件

// keystatic.config.ts
import { config, fields, collection } from '@keystatic/core';

export default config({
  storage: {
    kind: 'local',
  },
  collections: {
    posts: collection({
      label: 'Posts',
      slugField: 'title',
      path: 'src/content/posts/*',
      format: { contentField: 'content' },
      schema: {
        title: fields.slug({ name: { label: 'Title' } }),
        content: fields.markdoc({ label: 'Content' }),
      },
    }),
  },
});

具体的字段,可以让 Ai 帮你写。

配置完,访问:http://localhost:4321/keystatic

即能打开你 Astro 的 keystatic 后台了。其界面也算简洁美观了。

3. 远程部署

Keystatic 可以部署到 Vercel、Cloudflare Pages、Netlify 等免费 Serverless 平台上。

本次尝试部署到 Cloudflare Pages 上。此时有两种部署方式,一是使用 GitHub 模式,二是使用 Keystatic Cloud 模式,下面是其简单对比:

比较维度GitHub 模式 (kind: ‘github’)Cloud 模式 (kind: ‘cloud’)
本质你自己配置一个 GitHub App使用 Keystatic 官方的 GitHub App
上手难度。你得去 GitHub 设置 OAuth 密钥、环境变量、Webhook 等。极低。在官网点点鼠标,复制一个 Project ID 搞定。免费版可以添加最多3个用户.
鉴权逻辑每个团队成员都必须有该 GitHub 仓库的写权限。成员通过 Keystatic Cloud 登录,不需要 GitHub 权限(由 Cloud 统一操作)。
额外功能纯内容同步。Cloud Images。能自动优化图片,不让仓库因大图变得臃肿。

因为,如果使用 Keystatic Cloud 模式,即引入了第三方服务,从隐私方面考虑,本次决定先尝试使用 GitHub 模式

(1). 手动配置 @astrojs/cloudflare

执行:

npx astro add cloudflare

(2). 修改 astro.config.mjs

示例如下:

import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare'; // 必须显式引入
import keystatic from '@keystatic/astro';

export default defineConfig({
  output: 'server',
  adapter: cloudflare({
    platformProxy: { enabled: true }, // 方便本地模拟 CF 环境
  }),
  integrations: [
    keystatic(),
    // ... 其他合并后的 plugins
  ],
});

(3). 去 GitHub 申请“通行证” (GitHub App)

  1. 新建 App:去 GitHub Settings -> Developer settings -> GitHub Apps -> New GitHub App。
  2. 设置权限:你要给这个 App “Contents: Read & Write” 权限,否则它没法帮你发文章。
  3. 回调地址 (Callback URL):这是最容易错的地方。你必须填入你的真实域名: https://你的自定义域名/api/keystatic/github/oauth/callback
  4. 生成秘钥:你会得到一个 Client ID 和一个 Client Secret(这是一串乱码,只显示一次)。

(4):在部署平台 CF 录入变量

你得在 Cloudflare Pages 的后台,手动录入这些像“通关密码”一样的环境变量:

  1. KEYSTATIC_GITHUB_CLIENT_ID = 你的ID
  2. KEYSTATIC_GITHUB_CLIENT_SECRET = 你的秘钥
  3. KEYSTATIC_SECRET = 一段你自己随便编的随机字符串(用于加密 Cookie)

完善上述所有操作后,尝试访问网站后台:https://域名/api/keystatic

(5). 结果

一顿混乱,不停遇到各种报错,包括:

  • CF 部署失败;
  • CF 部署成功,但是打开网站,显示:Error 1101 Worker threw exception;
  • CF 部署成功,网站正常打开,但是后台地址,显示:[object Object]
    • 尝试 修改 Cloudflare 的兼容性 Flag:
      • 在 Cloudflare Pages 的 Settings -> Functions -> Compatibility Flags 中,手动添加这一条:disable_nodejs_process_v2
    • 修改后,后台页面不再显示 [object Object],而是显示,login with github,但是,点击后,又显示:Authorization failed
    • Ai 说是:@keystatic/astro 5.x 已知 bug,要降到 4.x 版本;按其给的代码修改,“@keystatic/core”: “^4.5.0”, // 或最新 4.x,和 “@keystatic/astro”: “^4.x.x” // 匹配对应版本 --- 结果,很坑爹: CF 部署直接报错!

避坑

  1. 在 Astro 5.x 里,output 的选项只剩下两个:
  • static: 全部静态。
  • server: 开启服务端能力(包括原来的 serverhybrid)。

4. 总结:

一顿操作猛如虎,折腾大半天,愣是搞不定,Keystatic 官网以及网上几乎没有相关教程,ai 更是坑爹,纯纯的浪费时间。

暂时只能放弃部署 Keystatic,有大佬知道怎么回事的,请在评论区指点一下吧。

Astro Keystatic CMS