Skip to content

fix(docs): 构建前把 static/img 拷进 rspress 的 public 根,修 docs-deploy 连红 - #1334

Merged
deepcoldy merged 1 commit into
masterfrom
fix/docs-deploy-dead-images
Sep 9, 2026
Merged

fix(docs): 构建前把 static/img 拷进 rspress 的 public 根,修 docs-deploy 连红#1334
deepcoldy merged 1 commit into
masterfrom
fix/docs-deploy-dead-images

Conversation

@deepcoldy

Copy link
Copy Markdown
Owner

问题

docs-deploy workflow 连红 8 次、零成功,最早追到 97233b1f2#1194,2026-09-07 03:02),最新 690e9967b#1283)。因为它不在 ruleset 必需 check 里、且被 paths: [docs-site/**] 门控,所以从未挡过任何人合码,红着一直没人注意。

根因

不是「图没提交」,是目录约定对不上

rspress 报 Dead image found。文档里写 ![..](/img/foo.png),而 rspress.config.tsroot: 'docs' ⟹ rspress 的 public 根是 docs-site/docs/public/,它就去那儿找(报错信息把期望路径逐字打出来了)。但截图实际提交在 docs-site/static/img/没有任何步骤把它们拷过去。而 markdown.link.checkDeadLinks 是开着的 ⟹ 一张缺图让整个站构建失败

docs/public 本来就是「构建前生成」的目录——它已在 docs-site/.gitignore 里,prebuild 钩子的 scripts/prepare-assets.mjs 会往里拷 logo。只是这个脚本只管了 logo。

现存 4 张死图,由三个 PR 陆续引入:

引入 被引用于
sessions-command-card.png #1194 {zh,en}/slash-commands.md
quota-fallback-dashboard.png #1283 {zh,en}/bots-json.md
quota-fallback-cycle-recovery-dashboard.png #1283 {zh,en}/bots-json.md
streaming-card-button-settings.png #1323 zh/bots-json.md

三个 PR 各自踩同一个坑 ⟹ 说明该结构性修掉,而不是逐张挪文件。

改法

prepare-assets.mjs 改成把整个 static/img/ 目录拷进 docs/public/img/,以后加截图不用再动这个脚本。

两个边界处理:

  • static/img 是唯一事实来源;生成出来的 docs/public/img/ 加进 .gitignore,避免同一批图在仓库里存两份(与既有的 docs/public/botmux-logo.png 那行同一套路)
  • 目录不存在时按 ENOENT 跳过、不让 prebuild 崩:没有截图的构建是合法的,「文档引用了但缺图」该由 rspress 的 checkDeadLinks 去管。(这一条是探针逼出来的:第一版会在 static/img 缺失时 ENOENT 退出 1,等于给构建加了一个它原本没有的失败模式。)

影响面

只动 docs 站构建的前置脚本与其 .gitignore不碰任何产品代码——与 daemon / worker / CLI 适配器 / 会话后端 / 飞书链路无关,不影响 ci.ymlbuildtest

妙搭发布链路无影响deploy.sh 推的是 doc_build/static(构建产物),与本 PR 动的源目录 docs-site/static/img 是两回事,同名但不相干。

验证

⚠️ 本地跑不了 rspress:worktree 里没有 docs-site/node_modules,而 CLAUDE.md 铁律是 worktree 内绝不跑 install。所以下面是脚本级 + 引用解析级验证,真正的绿要靠 CI 跑一次 docs-deploy 确认

结果
node scripts/prepare-assets.mjs rc=0,5 张图拷入 docs/public/img/
拷贝与源是否一致 md5 逐个相同,无 MISMATCH
文档里 4 个 /img/ 引用 全部解析到实际文件(unresolved=0)
删掉 static/img 重跑 rc=0(不再 ENOENT 崩);恢复后仍拷齐 5 张
生成目录是否被忽略 git check-ignore 命中 docs-site/.gitignore:5

后续(本 PR 不做)

修绿之后可以考虑把 deploy 加进 ruleset 必需 check,否则它以后照样会静默红着。但必须先修绿再加——否则会把所有产不出该 check 的在途 PR 卡死(#1288 刚踩过一次)。

🤖 Generated with Claude Code

`docs-deploy` 自 #1194 起 8 次 run 全部失败,零成功。报错是 rspress 的
`Dead image found`:文档里 `![..](/img/foo.png)` 会让 rspress 去
`docs-site/docs/public/img/` 找(`rspress.config.ts` 是 `root: 'docs'`),
而截图实际提交在 `docs-site/static/img/`,没有任何步骤把它们拷过去。
`markdown.link.checkDeadLinks` 开着,于是一张缺图就让整个站构建失败。

`docs/public` 本来就是「构建前生成」的目录(已在 .gitignore 里,`prebuild`
的 prepare-assets.mjs 会往里拷 logo),只是这个脚本只管了 logo。改成整个
`static/img/` 目录一起拷,以后加截图不用再动这个脚本——现存 4 张死图
(sessions-command-card、quota-fallback-dashboard、
quota-fallback-cycle-recovery-dashboard、streaming-card-button-settings,
分别由 #1194 / #1283 / #1323 引入)一并修好。

`static/img` 仍是唯一事实来源;生成出来的 `docs/public/img/` 加进 .gitignore,
避免同一批图在仓库里存两份。目录不存在时按 ENOENT 跳过而不是让 prebuild 崩掉:
没有截图的构建是合法的,该由 rspress 的 checkDeadLinks 去管「文档引用了但缺图」。

验证(本地无法跑 rspress:worktree 内不装依赖):
- `node scripts/prepare-assets.mjs` rc=0,5 张图拷进 docs/public/img/,与源逐字节相同
- 文档里 4 个 `/img/` 引用全部解析到实际文件(unresolved=0)
- 删掉 static/img 重跑 rc=0(不再 ENOENT 崩),恢复后仍拷齐 5 张
- 生成目录已被 .gitignore 忽略(`git check-ignore` 命中)
真正的绿要靠 CI 跑一次 docs-deploy 确认。

Co-Authored-By: Claude Code <noreply@anthropic.com>
@deepcoldy

Copy link
Copy Markdown
Owner Author

补充:已在干净 checkout 上做完真实 A/B,不再是「本地无法验证」

PR 描述里我写了「本地跑不了 rspress、真绿要靠 CI」。现在补上了真实构建验证 —— 做法是把 docs-sitegit archive 导出到 /tmp临时目录再装依赖,所以没有违反 CLAUDE.md「worktree 内绝不跑 install」(worktree 里至今没有 docs-site/node_modules,已核)。

决定性 A/B(两棵同样干净的 master 树,唯一差异是这一个文件)

prepare-assets.mjs 构建结果 Dead image 报错
对照(master 原样) 只拷 logo RC=1 失败 12 条
本 PR static/img/ 一起拷 RC=0 成功 0 条

对照组报错的 4 个文件与 CI 上逐字一致docs/{zh,en}/bots-json.mddocs/{zh,en}/slash-commands.md本地复现了 CI 的失败,不是「换了个环境所以绿了」。

不只是「不报错」,图真的进了产物

产物路径 大小 与源一致
sessions-command-card.png img/… 45589 B ✅ md5 相同
quota-fallback-dashboard.png img/… 191404 B
quota-fallback-cycle-recovery-dashboard.png img/… 186041 B
streaming-card-button-settings.png img/… 43563 B ✅ md5 相同

一个自我更正

我最初跑的那组对照是哑弹:在同一个目录里先跑了带修复的构建、再把脚本换回 master 版重跑,结果照样绿dead_image_errors=0)——因为上一次构建留下的 docs/public/img/ 等状态还在,等于让对照组白捡了修复的产物。换成 git archive 出来的全新目录才复现出 RC=1 / 12 条报错。

教训:验「去掉修复会不会转红」必须用未被前一次构建污染的树,同目录里前后跑两次是不够的。

环境差异(如实说明)

本地 pnpm 是 9.15.9,CI 用 npm i -g pnpm@9.5.0(我这台机器全局装失败,回退到已有版本)。pnpm install --frozen-lockfile rc=0、lockfile 未变,且 rspress 版本与 CI 报错路径里的 @rspress/core 2.0.13 一致,所以这个差异不影响本次结论;但严格意义上最终仍以 CI 的 docs-deploy 跑绿为准

⚠️ 另外说明:docs-deploy.ymlpush: branches:[master] + paths 触发,PR 上不会产出这条 check,所以合并前 CI 无法证明它绿——这也是我特意补做本地 A/B 的原因。它的 workflow_dispatch 会真的往 deepcoldy.github.io 发布,未经授权我不会去点。

@deepcoldy
deepcoldy merged commit 9387fa1 into master Sep 9, 2026
13 of 14 checks passed
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

🚀 Released in v3.21.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant