Repository Wiki
LyraVoid/Mizuki

内容仓库分离与同步机制

Mizuki 支持将博客内容(文章与图片)从站点代码仓库中剥离,放入独立的内容仓库进行版本管理,并通过 predev/prebuild 生命周期钩子在每次开发与构建前自动把远程内容同步到本地 CONTENT_DIR,最终交由 Astro 内容层消费。本页完整说明这一机制的配置、触发链路、同步行为、副作用与模式切换。

目的与范围

本页覆盖"内容仓库分离与同步"这一完整机制,包括:

  • ENABLE_CONTENT_SYNC 总开关的语义与取值行为
  • .env 中的三项核心配置:ENABLE_CONTENT_SYNC、CONTENT_REPO_URL、CONTENT_DIR
  • 同步触发链路:pnpm dev / pnpm build 如何通过 predev / prebuild 钩子自动执行 scripts/sync-content.js
  • 同步脚本的行为与副作用:git fetch + reset、.backup 备份、junction、复制文件、在代码仓库提交同步结果
  • 私有内容仓库的三种认证方式(HTTPS / SSH / Token)
  • 本地模式与分离模式之间的切换流程
  • 常用命令、故障模式与运维注意事项

以下相关主题有意留给兄弟页面,本页仅作指引:

证据边界说明:本页对同步行为的描述,取自仓库内的权威规范文档 docs/CONTENT_SEPARATION.md 与 package.json 中的脚本接线;scripts/sync-content.js 的内部逐行实现(例如具体分支判断代码)未在本页逐行摘录,以源文件为准。

概述

解决什么问题

在一个"代码 + 内容"混合的静态博客仓库中,常见三类痛点:

  1. 协作冲突:多位作者同时提交文章时,与代码改动混在同一个仓库与同一条提交历史中。
  2. 私有内容:希望文章仓库私有,而站点主题代码保持公开。
  3. 版本控制粒度:内容与代码希望各自独立演进、独立回滚。

Mizuki 的解法是内容分离:内容放入独立仓库(例如 Mizuki-Content),本地通过 CONTENT_DIR(默认 ./content)承接同步结果,开发与构建入口在启动前自动执行同步,开发者几乎无感。

关键概念

概念含义
本地模式ENABLE_CONTENT_SYNC=false,内容直接放在 src/content/ 与 public/images/,与代码同仓库管理
分离模式ENABLE_CONTENT_SYNC=true,内容来自远程内容仓库,同步到 CONTENT_DIR
同步副作用同步脚本可能 fetch + reset 内容目录、生成 .backup 备份、创建 junction 或复制文件,并把同步结果提交到代码仓库
生命周期钩子npm 的 predev / prebuild 机制,在 pnpm dev / pnpm build 之前自动运行同步脚本

适用场景

  • 个人博客、内容较少:本地模式,零配置(仓库文档将其列为新手推荐)
  • 团队协作、私有内容、大量文章:分离模式

架构

Loading diagram...

架构说明

  • 配置层:唯一的开关与参数来源是项目根目录 .env。三个变量共同决定同步脚本走哪条路径。
  • 脚本接线层:package.json 通过 npm 生命周期约定把同步"织入"日常命令——predev 与 prebuild 分别在 pnpm dev 与 pnpm build 之前自动执行同步脚本,且都带 || true 容错(同步失败不会中断开发/构建)。sync-content 与 init-content 则提供手动入口。
  • 同步层:scripts/sync-content.js 是同步的核心执行者;scripts/init-content-repo.js 负责初始化/创建内容仓库(迁移场景使用)。
  • 内容存储层:分离模式下内容落在 CONTENT_DIR(默认 ./content);本地模式下内容位于 src/content/ 与 public/images/。同步过程可能产生 .backup 备份。
  • 远程仓库层:内容仓库与代码仓库物理隔离;同步结果会被提交回代码仓库(这意味着映射产物对代码仓库可见)。
  • 构建层:无论哪种模式,最终都汇入 Astro 内容层,对渲染管线而言来源是透明的。

设计意图:把"内容来源"抽象为环境变量驱动的开关,而不是两套站点模板。开发者切换模式不需要改代码,只改 .env;把同步挂在生命周期钩子上,则保证"启动前内容一定最新",避免开发者忘记手动同步。

核心流程

触发链路:一次 pnpm dev 背后发生了什么

Loading diagram...

分步说明

  1. 入口:开发者执行 pnpm dev 或 pnpm build。npm/pnpm 会按约定先运行同名 pre 钩子,即 predev / prebuild,两者都指向同一个同步脚本。
  2. 读取开关:脚本读取 .env 中的 ENABLE_CONTENT_SYNC。这是唯一的模式判据——没有第二处配置。
  3. 本地模式(false):跳过同步,直接使用 src/content/ 与 public/images/ 中的本地内容。
  4. 分离模式(true):读取 CONTENT_REPO_URL 与 CONTENT_DIR,与远程内容仓库交互。
  5. 同步副作用(来自仓库文档的明确警示):当 CONTENT_DIR 已经是 Git 仓库时,脚本会 fetch 并将其重置到远程 main 或 master 分支;建立运行时映射时,可能将已有目录备份为 .backup、创建 junction 或复制文件,并在代码仓库中提交同步结果。因此运行前应提交或备份本地修改,且不要直接编辑同步目标。
  6. 容错退出:无论同步是否成功,predev/prebuild 中的 || true 保证钩子退出码为 0,不会阻断开发/构建。
  7. 启动构建:Astro 从 CONTENT_DIR(分离模式)或本地目录(本地模式)读取内容并渲染。

为什么这样设计:|| true 是一个刻意的取舍——内容同步失败(例如断网、私有仓库未授权)不应让开发者完全无法启动本地预览;代价是同步错误可能被吞掉,需要靠脚本自身的日志输出提醒,这也是文档"故障排查"一节存在的原因。

使用示例

示例 1:本地模式(零配置,新手推荐)

bash
1# 克隆项目 2git clone https://github.com/LyraVoid/Mizuki.git 3cd Mizuki 4 5# 安装依赖 6pnpm install 7 8# 直接开发 9pnpm dev

内容存放在 src/content/ 和 public/images/ 目录,与代码一起管理。

Source: CONTENT_SEPARATION.md

示例 2:启用内容分离

bash
1# 1. 创建 .env 文件 2cp .env.example .env 3 4# 2. 编辑 .env,启用内容分离 5ENABLE_CONTENT_SYNC=true 6CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git 7 8# 3. 同步内容 9pnpm run sync-content 10 11# 4. 启动开发 12pnpm dev

Source: CONTENT_SEPARATION.md

示例 3:同步脚本在 package.json 中的接线

json
1{ 2 "scripts": { 3 "sync-content": "node scripts/sync-content.js", 4 "init-content": "node scripts/init-content-repo.js", 5 "predev": "node scripts/sync-content.js || true", 6 "prebuild": "node scripts/sync-content.js || true" 7 } 8}

Source: package.json

这一段是整个机制的"心脏":predev/prebuild 把同步注入到日常命令,|| true 提供容错。要临时跳过自动同步,可以不走 pnpm dev 而直接调用 astro 命令,或临时将 ENABLE_CONTENT_SYNC 置为 false。

示例 4:分离模式下在内容仓库中工作

bash
1# 自动同步内容后启动 2pnpm dev 3 4# 内容在独立仓库编辑 5cd /path/to/Mizuki-Content 6# 编辑文章 7git add . 8git commit -m "Update article" 9git push

Source: CONTENT_SEPARATION.md

配置选项

所有配置位于项目根目录 .env 文件中:

选项类型默认值说明
ENABLE_CONTENT_SYNCstring ("true" / "false")未设置时进入同步逻辑内容分离总开关。false = 使用本地内容;true = 从远程仓库同步。未设置或其他值会进入同步逻辑,本地开发建议显式设为 false
CONTENT_REPO_URLstring (Git URL)无(ENABLE_CONTENT_SYNC=true 时必填)内容仓库地址。支持 HTTPS、SSH、Token 方式
CONTENT_DIRstring (路径)./content同步目标目录路径,一般无需改动

CONTENT_REPO_URL 支持的地址格式

格式适用场景
https://github.com/username/repo.git公开仓库
git@github.com:username/repo.git私有仓库(SSH)
https://TOKEN@github.com/username/repo.git私有仓库(Token)

ENABLE_CONTENT_SYNC 取值行为对照

值行为适用场景
false禁用内容分离,使用本地内容本地内容、个人博客、内容较少
true启用内容分离,从远程仓库同步团队协作、私有内容、大量文章
未设置或其他值进入同步逻辑;无内容仓库地址时通常继续使用本地内容,但会输出提示不推荐,建议显式设置避免误解

模式切换

从本地切换到独立仓库

  1. 创建内容仓库(参考仓库文档 MIGRATION_GUIDE.md)
  2. 编辑 .env:
bash
ENABLE_CONTENT_SYNC=true CONTENT_REPO_URL=https://github.com/your-username/Mizuki-Content.git
  1. 同步内容:pnpm run sync-content

从独立仓库切换回本地

  1. 编辑 .env:
bash
ENABLE_CONTENT_SYNC=false
  1. 直接开发:pnpm dev

Source: CONTENT_SEPARATION.md

常用命令参考

命令说明
pnpm run sync-content手动执行内容同步(node scripts/sync-content.js)
pnpm run init-content初始化/创建内容仓库(node scripts/init-content-repo.js,迁移场景)
pnpm dev开发启动;前置 predev 自动同步(`
pnpm build构建;前置 prebuild 自动同步(`

Source: package.json

故障模式、边界情况与并发

故障模式

症状根因处理建议
同步失败但 dev/build 仍继续predev/prebuild 中的 || true 吞掉了非零退出码关注脚本日志输出;手动运行 pnpm run sync-content 查看真实错误
CONTENT_DIR 本地修改被覆盖分离模式下脚本会 fetch 并 reset 到远程 main/master运行前提交或备份本地修改;不要直接编辑同步目标
已有目录被备份为 .backup建立运行时映射时脚本的备份副作用属预期行为;如需保留请在同步前自行备份
本地开发误入同步逻辑ENABLE_CONTENT_SYNC 未设置时脚本仍进入同步逻辑本地显式设置 ENABLE_CONTENT_SYNC=false
私有仓库无法拉取认证未配置或 Token 失效按上表选择 SSH 或 Token 格式;确保凭据可用
Windows 下目录映射异常junction 创建失败或权限不足手动清理后重试 pnpm run sync-content

关键边界情况

  • 开关语义不对称:只有显式的 false 才表示禁用;"未设置"并不等于"关闭",而是会进入同步逻辑(无地址时降级为本地内容并提示)。这是最容易踩的坑。
  • 同步目标是只读的:分离模式下 CONTENT_DIR 由远程仓库定义其真实状态,本地直接编辑会在下一次 fetch+reset 时丢失。
  • 同步结果会进入代码仓库:映射产物(junction/复制文件等)会被提交到 Mizuki 代码仓库,团队协作时需要注意这部分提交的语义。

并发与一致性

  • 重复触发:pnpm dev 与 pnpm build 各自触发一次同步;若同时运行多个 dev 实例,可能并发执行同步脚本。由于脚本以 fetch+reset 为最终一致性手段,结果收敛到远程 main/master,但过程中可能出现短暂的目录状态抖动。
  • 提交竞争:同步脚本会在代码仓库中提交同步结果。若开发者本地有未提交改动,或多人/多进程同时触发同步,代码仓库一侧可能出现提交交错,建议在干净工作区执行同步。

性能与运维注意事项

  • 每次 dev/build 都会同步:同步开销随内容仓库体积增长。内容极大时,可通过临时置 ENABLE_CONTENT_SYNC=false 跳过同步以加快启动(代价是需自行保证内容新鲜度)。
  • CI/CD 环境:prebuild 中的 || true 意味着 CI 构建即使同步失败也会继续,可能用旧内容或空内容构建。生产流水线应在构建前显式执行 pnpm run sync-content 并检查其退出码,而不是依赖钩子的容错。CI/CD 部署的完整说明见仓库文档 CONTENT_SEPARATION.md 的 CI/CD 部署章节。
  • 凭据管理:Token 形式的 CONTENT_REPO_URL 含敏感信息,不应提交到代码仓库;仅在 .env(通常被 gitignore)中维护。
  • 自动构建联动:内容仓库更新后如何触发站点自动构建,见 AUTO_BUILD_TRIGGER.md。

扩展点

  • 自定义同步目标:CONTENT_DIR 允许将同步内容落到非默认路径(默认 ./content),文档标注"一般无需改动"。
  • 初始化脚本:scripts/init-content-repo.js 提供了从现有仓库抽取内容建立独立内容仓库的入口,是实施分离迁移的扩展路径(配合 MIGRATION_GUIDE.md)。
  • 替换同步实现:由于同步完全通过 npm 生命周期钩子注入,理论上可修改 package.json 中的 predev/prebuild 指向自定义脚本,而不影响 Astro 构建层。

相关链接

Sources

(1 files)