Files
docusaurus/docs/Docusaurus资料/cms构建说明.md
T
linghutianhao 5c4a471280 测试OAuth2
2026-08-14 17:16:25 +08:00

11 KiB
Raw Blame History

title, sidebar_position
title sidebar_position
cms构建说明 10

cms

sveltia-cms

1.文件
新增 static/admin/index.html  sveltia CMS入口页,CDN方式
新增 static/admin/config.yml  sveltia全部配置

2.访问
http://localhost:3000/admin/

decap-cms(仅本地)

https://decapcms.org/docs/basic-steps/

1.文件
新增 static/admin/index.html  Decap CMS入口页,CDN方式
新增 static/admin/config.yml  Decap全部配置
修改 package.json 增加"cms": "npx decap-server"

2.内容
docs的文件要增加 title

3.启动
npx decap-server  或 npm run cms

4.访问
http://localhost:3000/admin/

已创建的文件

文件 说明
static/admin/index.html Decap CMS 入口,从 CDN 加载
static/admin/config.yml 核心配置:backend、集合、媒体文件路径
server.js Gitee OAuth 认证代理服务(生产环境用)
.env.example 环境变量模板

Git 仓库

已本地提交并推送到 git@gitee.com:lhth/testdecap.git

有一个新的更改(导航栏链接改到 Gitee)在本地但被拦截了,你需要手动推一下:

cd "d:/projects/test/my-websitetest"
git push origin master

架构说明

当前配置(开发/测试):proxy backend

浏览器 → Decap CMS → proxy:8081 → 本地 git repo → SSH → Gitee

运行方式:

# 终端 1:启动 Docusaurus
npm start

# 终端 2:启动 Decap 代理(在项目根目录)
npx decap-server

# 访问 http://localhost:3000/admin/ 即可使用 CMS

注意Docusaurus 开发服务器的 SPA 路由会拦截 /admin/ 路径。有两个解决办法:

  1. 访问 http://localhost:3000/admin/index.html (可能仍会被拦截)
  2. 用生产模式:npm run build && npm run serve,然后访问 http://localhost:3000/admin/ (已验证可行)

生产环境部署(Gitee OAuth

当你要部署到远程服务器时,需要:

1. 在 Gitee 创建 OAuth App

2. 部署认证服务

# 服务器上运行
GITEE_CLIENT_ID=xxx GITEE_CLIENT_SECRET=xxx node server.js

或者部署到 Vercel/Cloudflare Workers 等 Serverless 平台。

3. 修改 config.yml 取消注释文末的生产环境配置,注释掉 proxy backend 部分(文件中已有注释说明)。

内容集合

已配置两个集合:

  • 博客文章 (blog/) — Docusaurus 标准 YYYY-MM-DD-title.md 格式
  • 文档 (docs/) — Docusaurus 文档格式

你可以随时在 static/admin/config.yml 中增删字段或集合。

浏览器                     本地机器                  Gitee
 ┌─────────┐            ┌──────────────┐         ┌──────────┐
 │ Decap   │──proxy──→  │ decap-server │──git──→ │ gitee.com│
 │ CMS UI  │  HTTP:8081 │ (本地Node进程) │  SSH   │ (你的仓库)│
 │ admin/  │            │ 读写本地git   │         │          │
 └────┬────┘            └──────────────┘         └──────────┘
      │
      └── unpkg.com CDN (加载 decap-cms.js)

sveltia-cms + gitea(当前使用)

Sveltia CMS 直接对接 Gitea:浏览器登录 Gitea(OAuth2 隐式授权),编辑内容保存后直接提交到 Gitea 仓库。

浏览器 → Sveltia CMS UI (localhost:3000/admin) → Gitea API (115.190.192.69:3011)
                                              → OAuth 登录 → 直接 commit/push

配置(static/admin/config.yaml

backend:
  name: gitea
  repo: admin/docusaurus
  branch: main
  base_url: http://115.190.192.69:3011
  auth_endpoint: /login/oauth/authorize
  auth_scope: read_user,write:repository

Gitea 侧要做两件事(一次性):

  1. 创建 OAuth2 应用

    • 登录 Gitea → 头像 → 设置 → 应用 → 管理 OAuth2 应用程序 → 创建新应用
    • 应用名称:Sveltia CMS
    • 重定向 URIhttp://localhost:3000/admin/(必须与访问 CMS 的地址完全一致,含结尾斜杠;以后换域名/端口要回来改)
    • 创建后复制 Client ID,填到 static/admin/config.yamlbackend.client_id(去掉注释)(隐式授权不需要 Secret)
  2. 开启 CORS(改 Gitea 服务器上的 app.ini,然后重启 Gitea

    [cors]
    ENABLED = true
    SCHEME = http
    ALLOW_DOMAIN = localhost:3000
    ALLOW_SUBDOMAIN = false
    METHODS = GET,POST,PUT,PATCH,DELETE,OPTIONS
    MAX_AGE = 600
    ALLOW_CREDENTIALS = false
    

    app.ini 位置:Windows 一般在 C:\Program Files\Gitea\custom\conf\app.iniLinux 在 /etc/gitea/app.ini;也可以在 Gitea 后台「站点管理 → 配置」里看到实际路径。 若从局域网其他电脑访问,把 ALLOW_DOMAIN 改成对应主机名/IP。

启动与访问

npm start
# 打开 http://localhost:3000/admin/index.html (若 /admin/ 被 Docusaurus 路由拦截就用这个)

点 Login with Gitea → 授权后即可编辑,保存即提交到 admin/docusaurusmain 分支。

排错

  • 登录跳转后报 invalid client / 授权页打不开:client_id 没填或填错 → 检查 backend.client_id
  • 登录成功但列表/保存报 CORS 错误(控制台 Access-Control-Allow-Origin):Gitea 的 [cors] 没开或 ALLOW_DOMAIN 没包含 localhost:3000,或 Gitea 没重启
  • 重定向 URI 不匹配(Gitea 报 invalid redirect_uri):Gitea 里 OAuth 应用的重定向 URI 必须与浏览器地址栏实际访问的 CMS 地址逐字符一致
  • 分支不对:确认 branch: main 与仓库默认分支一致

部署到服务器(115.190.192.69,站点 3000 端口 / Gitea 3011 端口)

站点和 Gitea 放同一台服务器,浏览器访问 http://115.190.192.69:3000/admin/CMS 直连 Gitea3011)。

1. 构建

npm run build        # 产物在 build/

2. 把代码弄到服务器(推荐源码方式,便于后续自动重建)

# 服务器上(需装 node ≥ 20)
git clone http://115.190.192.69:3011/admin/docusaurus.git
cd docusaurus
npm install

3. 启动站点(3000 端口)

npm run build && npm run serve -- --host 0.0.0.0 --port 3000
# 或用 nginx/caddy 把 build/ 目录静态托管在 3000 端口
# 防火墙放行 3000 端口

4. Gitea 侧(一次性,改完重启 Gitea)

  • OAuth 应用的重定向 URI 加一行:http://115.190.192.69:3000/admin/(本地调试的 http://localhost:3000/admin/ 可保留,多行添加)

  • app.ini 的 CORS

    [cors]
    ENABLED = true
    SCHEME = http
    ALLOW_DOMAIN = 115.190.192.69:3000
    ALLOW_SUBDOMAIN = false
    METHODS = GET,POST,PUT,PATCH,DELETE,OPTIONS
    MAX_AGE = 600
    ALLOW_CREDENTIALS = false
    

5. 访问 http://115.190.192.69:3000/admin/ → Login with Gitea

内容更新闭环(关键)

CMS 里保存 = 直接 commit 到 Gitea 仓库,但静态站点不会自动更新,需要服务器重建:

  • 方案 A(推荐)Gitea 建 Push WebhookURL 指向服务器上的小脚本,如 http://115.190.192.69:8080/hook),脚本收到推送后执行 git pull && npm run build,再重启/重载静态服务
  • 方案 B(手动):改完内容后 SSH 上服务器 git pull && npm run build
  • 方案 C(省事):服务器定时任务每分钟 git pull,有变更才 build

tina-cms(卡)

https://tina.io/docs/reference/config

1.npm install tinacms @tinacms/cli
2.tina/config.js
3.package.json
	// scripts 里加
    "tina": "tinacms dev -c \"docusaurus start\"",
4.npm run tina
	自动生成tina/__generated__/
            ├── _graphql.json
            ├── _lookup.json
            ├── _schema.json
            ├── client.ts
            ├── config.prebuild.jsx
            ├── frags.gql
            ├── queries.gql
            ├── schema.gql
            ├── static-media.json
            ├── types.js
            └── types.ts
5.npm run tina
# 官方提供标准版
const branch =
  process.env.NEXT_PUBLIC_TINA_BRANCH ||
  process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_REF ||
  process.env.HEAD ||
  'main';

export default defineConfig({
  branch,
  // generated by TinaCloud
  token: '<Your Read Only Token>',
  // generated by TinaCloud
  clientId: '<Your Client ID>',
  build: {
    publicFolder: 'public',
    outputFolder: 'admin',
  },
  schema: {
    //Content model definition here...
  },
  ui: {
    previewUrl: (context) => {
      // Use Vercel preview deployments based on branch names
      return { url: `https://my-app-git-${context.branch}.vercel.app` };
    },
  },
  media: {
    tina: {
      publicFolder: 'public',
      mediaRoot: 'uploads',
    },
  },
  search: {
    tina: {
      indexerToken: process.env.TINA_SEARCH_TOKEN,
    },
  },
});
import { defineConfig } from "tinacms";

export default defineConfig({
  branch: process.env.TINA_BRANCH || "master",
  clientId: process.env.TINA_CLIENT_ID || "",
  token: process.env.TINA_TOKEN || "",
  build: {
    publicFolder: "static",
    outputFolder: "admin",
  },
  media: {
    tina: {
      mediaRoot: "img",
      publicFolder: "static",
      static: true,
    },
  },
  schema: {
    collections: [
      {
        name: "blog",
        label: "博客",
        path: "blog",
        format: "md",
        fields: [
          { type: "string", name: "title", label: "标题", isTitle: true, required: true },
          { type: "datetime", name: "date", label: "发布日期", ui: { dateFormat: "YYYY-MM-DD", timeFormat: false } },
          { type: "string", name: "tags", label: "标签", list: true, ui: { component: "tags" } },
          { type: "string", name: "description", label: "描述/摘要" },
          { type: "rich-text", name: "body", label: "正文", isBody: true },
        ],
      },
      {
        name: "docs",
        label: "文档",
        path: "docs",
        format: "md",
        fields: [
          { type: "string", name: "title", label: "标题", isTitle: true, required: true },
          { type: "number", name: "sidebar_position", label: "侧边栏位置" },
          { type: "string", name: "tags", label: "标签", list: true, ui: { component: "tags" } },
          { type: "rich-text", name: "body", label: "正文", isBody: true },
        ],
      },
    ],
  },
});