Skip to content

构建、预览、审计与发布完整流程 ​

读者对象:已经写好 Markdown,但还不知道如何把文章安全发布到本站的初学者。

本页按真实顺序讲清楚:本地开发、生产构建、SEO 审计、构建产物预览、Git 提交、CNB 自动构建、EdgeOne 部署、线上验收、缓存处理和回滚。

所有命令默认在项目根目录 teek-hyde 中执行。不要在其他目录执行,也不要把命令前面的 $ 或 PS> 一起复制。

如果还不熟悉正文写法,先阅读 Markdown 写作基础与本站扩展。

发布流程总览 ​

发布不是「保存 Markdown 文件」这么简单。本站使用 VitePress 生成静态站点,再由 CNB 和 EdgeOne 自动部署,完整链路是:

text
编写 Markdown
→ pnpm docs:dev 本地开发与检查
→ pnpm docs:build 生产构建
→ pnpm docs:audit 检查 dist 的 SEO 基线
→ pnpm docs:preview 预览生产构建
→ git add / git commit / git push origin main
→ CNB 自动安装依赖、重新构建、再次审计
→ EdgeOne Makers 发布 docs/.vitepress/dist
→ 在正式域名上验收

最重要的是顺序:

  1. 先在开发服务器里把内容和交互检查好;
  2. 再构建生产文件;
  3. 构建成功后才运行审计;
  4. 审计成功后预览构建产物;
  5. 最后才提交并推送;
  6. 推送后等待 CNB 和 EdgeOne 完成部署;
  7. 到线上做最终验收。

先认识这些术语 ​

术语通俗解释
Markdown用 #、列表、代码块等纯文本语法写内容的格式
VitePress把 Markdown 构建成静态网站的框架
Teek / Teek-Hyde本站使用的 VitePress 主题和定制层,决定页面布局、侧边栏、卡片外观等
开发服务器只在本机运行的服务,用来边改边看,默认端口 5174
HMRHot Module Replacement,热更新;保存文件后页面局部自动更新
生产构建把源码编译成可部署的 HTML、CSS、JavaScript 和静态资源
dist构建产物目录,本项目是 docs/.vitepress/dist
预览服务器不是开发服务器,只负责把 dist 当作静态网站提供服务,默认端口 4173
Pagefind本站使用的离线全文搜索索引生成器
SEO搜索引擎优化,包括标题、描述、canonical、sitemap 等
canonical告诉搜索引擎某个页面的正式 URL,避免重复收录
sitemap给搜索引擎的站点 URL 清单,本项目生成 sitemap.xml
RSS文章订阅源,本项目生成 feed.rss
锁文件pnpm-lock.yaml,记录依赖的精确版本,保证不同机器安装结果一致
CI/CD持续集成/持续部署,本项目使用 CNB 自动构建和部署
EdgeOne腾讯云边缘安全加速平台,本项目用 EdgeOne Makers 托管静态站点
CDN 缓存边缘节点保存的旧网页副本;部署后有时需要刷新

为什么本地开发不能直接当发布 ​

pnpm docs:dev 生成的是开发服务器内容,包含热更新和调试逻辑,不会生成完整的 docs/.vitepress/dist。线上需要的是生产构建和 Pagefind 索引,不是你的本地开发端口。

因此:

  • 本地能打开页面,只能证明内容大致可用;
  • 线上发布前必须执行 pnpm docs:build;
  • SEO 审计读取的是构建后的 dist;
  • 预览服务器读取的也是 dist;
  • 推送后 CNB 还会从源码重新构建一次。

准备开发环境 ​

第 1 步:检查 Node.js ​

本站依赖 Vite 7。当前项目安装的 Vite 版本要求 Node.js 满足:

text
^20.19.0 || >=22.12.0

推荐使用 Node.js 22 LTS,并满足 >=22.12.0。CNB 发布流水线也使用 Node 22 镜像。

在终端执行:

bash
node -v

预期看到类似:

text
v22.12.0

只要满足上面的版本范围即可。若版本太低,先升级 Node.js,再继续。Node.js 是运行 VitePress、Pagefind、构建脚本和 pnpm 的基础环境。

第 2 步:检查 pnpm ​

项目使用 pnpm,并通过 pnpm-lock.yaml 锁定依赖。执行:

bash
pnpm -v

预期看到类似:

text
10.x.x

只要能正常运行 pnpm 即可。没有安装时,可以按官方方式安装,CNB 中使用的是:

bash
npm install -g pnpm

不要在项目中使用 npm install 安装项目依赖,也不要混用 npm、yarn 和 pnpm。混用会生成不同结构的 node_modules,可能导致脚本失败或 lockfile 变化。

第 3 步:打开或克隆仓库 ​

已经拿到项目目录时:

powershell
cd E:\vitepress-teek-my-blog\teek-hyde

路径只是示例,请换成你的实际路径。

还没有仓库时:

bash
git clone <仓库地址> teek-hyde
cd teek-hyde

尖括号是占位符,必须替换成真实仓库地址,不要把尖括号原样执行。

进入目录后确认当前位置:

powershell
Get-Location

Git Bash、macOS 或 Linux 可以使用:

bash
pwd

预期看到仓库根目录,里面应有 docs/、package.json、pnpm-lock.yaml 和 .cnb.yml。

第 4 步:安装依赖 ​

首次拿到项目时:

bash
pnpm install

安装完成后应看到类似 Done in ... 的提示,并出现 node_modules/。

如果只是按锁文件还原一套完全一致的依赖:

bash
pnpm install --frozen-lockfile

两者区别:

命令作用何时使用
pnpm install根据 package.json 和 lockfile 安装;锁文件需要时会更新首次开发、确认要调整依赖时
pnpm install --frozen-lockfile严格按现有 lockfile 安装,不修改 lockfile;两者不一致就失败CI、干净环境、普通写文章时

本项目只是写文章时,不应该随意修改依赖。--frozen-lockfile 失败通常说明 package.json 与 pnpm-lock.yaml 不一致,不要用删除 lockfile 的办法掩盖问题。

node_modules/、dist/、缓存等生成目录不应提交到 Git。

环境准备常见错误 ​

现象原因处理
pnpm: command not found没安装 pnpm 或 PATH 未生效重新打开终端,检查 pnpm -v
ERR_PNPM_UNSUPPORTED_ENGINE 或 Vite 启动失败Node.js 版本过低升级到 Node 22 LTS 并重新打开终端
安装过程修改了 lockfile使用了 npm/yarn,或依赖声明与锁文件不一致确认使用 pnpm;不要提交无意产生的 lockfile 变化
--frozen-lockfile 失败依赖清单与锁文件不同步先理解原因;不要随意删除 lockfile 或强行绕过

四个核心命令 ​

项目 package.json 定义了四个命令:

命令实际执行内容端口作用什么时候用
pnpm docs:devvitepress dev docs默认 5174启动开发服务器,支持 HMR写文章、调样式、即时检查
pnpm docs:build以 4GB 内存上限运行 VitePress 构建无生成 docs/.vitepress/dist审计、预览和发布前
pnpm docs:previewvitepress preview docs默认 4173静态预览构建产物检查 dist 的真实效果
pnpm docs:auditnode scripts/audit-site.mjs无检查构建后的 SEO 与页面结构必须在本机构建后

开发端口来自 docs/.vitepress/config.ts:

ts
vite: {
  server: {
    host: "0.0.0.0",
    port: 5174,
    strictPort: false,
  },
}

strictPort: false 表示端口被占用时 Vite 可能自动尝试下一个端口。因此始终以终端打印的 Local: 地址为准,不要盲目认为一定是 5174。

预览端口 4173 是 VitePress 预览服务器的默认端口。可以用参数改成 4174,后文会给出完整命令。

为什么有四个命令 ​

  • docs:dev 速度快,但不等于生产结果;
  • docs:build 才生成可部署文件;
  • docs:audit 依赖构建产物,不能替代构建;
  • docs:preview 用来检查构建产物,不会重新编译源码。

四个命令不是互斥的四个网站,而是同一条发布链路的不同阶段。

本地开发:边写边看 ​

第 1 步:确认在项目根目录 ​

powershell
Get-Location

或:

bash
pwd

如果当前目录不是 teek-hyde,先 cd 回来。命令在错误目录执行时,常见表现是找不到 package.json 或 docs。

第 2 步:启动开发服务器 ​

bash
pnpm docs:dev

预期终端出现类似:

text
VITE v7.x.x  ready in ... ms

➜  Local:   http://localhost:5174/
➜  Network: http://192.168.x.x:5174/

如果 5174 被占用,实际端口可能不是 5174,以 Local: 为准。

第 3 步:在浏览器打开页面 ​

打开:

text
http://localhost:5174/

还可以直接打开写作相关内容:

text
http://localhost:5174/writing-guide/markdown-basics
http://localhost:5174/writing-guide/publishing

这里使用的是页面 frontmatter 中的 permalink,不带 .html。

第 4 步:验证 HMR ​

HMR 是热更新:修改已有 Markdown 的正文并保存后,浏览器页面通常会自动更新,不必每次都重启服务器。新增、删除或移动文章文件不属于普通正文热更新,见下一步。

可以这样测试:

  1. 打开一篇正在编辑的文章;
  2. 把某段正文改一个词;
  3. 保存文件;
  4. 观察浏览器是否自动更新;
  5. 再看终端是否出现重新编译提示。

如果只是普通正文修改,通常可以立即看到。如果页面没有更新,先看终端是否报错,再尝试普通刷新。

第 5 步:知道哪些修改需要重启 ​

以下变更通常不能只靠 HMR,需要停止再启动开发服务器:

  • docs/.vitepress/config.ts、plugins.ts、site.ts 等配置;
  • docs/.vitepress/sidebar.ts 生成逻辑;
  • docs/.vitepress/search-manifest.ts 生成逻辑;
  • 新增、删除或修改 catalogue: true 的目录页数据;
  • 新增、删除或移动文章文件;
  • 新增文章目录或大幅调整文章目录结构;
  • 插件、依赖、主题入口发生变化。

原因是这些数据往往在 Vite 启动或配置加载时扫描生成,不是单个 Markdown 文件的热更新范围。

第 6 步:停止服务器 ​

在运行开发服务器的终端按:

text
Ctrl+C

看到命令提示符重新出现,说明服务器已停止。不要直接关闭终端窗口后以为端口一定释放;有时后台进程还占用端口,后文故障排查会说明。

本地开发常见错误 ​

错误为什么会出问题正确做法
用 file:///.../index.html 打开没有经过 VitePress 服务器使用 http://localhost:端口/
端口写死成 5174端口被占用时 Vite 可能换了端口看终端 Local: 地址
修改 dist 里的文件dist 是构建产物,会被覆盖修改 docs/ 下的源码
新增目录后只刷新浏览器目录扫描数据没有重启生成停止后重新 pnpm docs:dev
在错误目录执行 pnpm找不到脚本或 docs先进入仓库根目录

生产构建:生成可部署文件 ​

第 1 步:保存所有修改 ​

构建读取磁盘上的文件。编辑器里没保存的内容不会被构建,因此先保存所有 Markdown、配置和图片。

第 2 步:执行生产构建 ​

在项目根目录运行:

bash
pnpm docs:build

这个脚本实际使用:

bash
node --max-old-space-size=4096 node_modules/vitepress/bin/vitepress.js build docs

--max-old-space-size=4096 给 Node.js 约 4GB 内存上限。首次构建会比 HMR 慢,因为它要生成完整页面、压缩资源、生成搜索索引、RSS 和 sitemap。

预期成功标志:

  • 进程正常结束并回到命令提示符;
  • 终端出现 VitePress 构建完成提示;
  • 终端出现 Pagefind 索引生成相关日志;
  • 看到 .gz 压缩输出也属正常;
  • docs/.vitepress/dist/ 存在且包含页面、资源、pagefind/、feed.rss、sitemap.xml 等文件。

如果只看到构建日志但最后有错误并以非零状态退出,就不是成功构建。不要继续审计或发布。

第 3 步:检查构建产物目录 ​

PowerShell:

powershell
Get-ChildItem docs\.vitepress\dist

Git Bash、macOS 或 Linux:

bash
ls docs/.vitepress/dist

会看到类似:

text
404.html
index.html
posts/
catalog/
writing-guide/
pagefind/
feed.rss
sitemap.xml
assets/

不同内容和插件版本可能导致具体文件名略有变化,这是正常的。

第 4 步:认识构建自动生成的文件 ​

产物位置作用是否手工编辑
HTML 页面docs/.vitepress/dist/**/*.html最终网页否
静态资源docs/.vitepress/dist/assets/、home/、images/ 等CSS、JS、图片等否
Pagefind 搜索索引docs/.vitepress/dist/pagefind/站内全文搜索否
RSS 订阅源docs/.vitepress/dist/feed.rss文章订阅否
sitemapdocs/.vitepress/dist/sitemap.xml给搜索引擎的 URL 清单否
搜索清单副本docs/.vitepress/dist/search-manifest.json从源文件生成并复制进 dist否
gzip 压缩文件带 .gz 的资源文件由压缩插件生成否

这些文件的源头分别是 Markdown、图片、VitePress 配置和插件配置。修改 dist 只是临时改一个会被下一次构建覆盖的副本,绝不能把它当成修复源码的方法。

第 5 步:理解 Pagefind、RSS 和 sitemap ​

Pagefind 搜索 ​

docs/.vitepress/plugins.ts 中配置了 Pagefind。它在构建阶段扫描页面并生成 dist/pagefind/ 索引;普通文章需要:

yaml
pagefind-indexed: true

写作指南页面当前使用 pagefind-indexed: false,所以不会进入搜索。这不是 bug,是页面类型的预期行为。

RSS ​

RSS 插件会生成:

text
docs/.vitepress/dist/feed.rss

线上地址是:

text
https://www.baecon.cn/feed.rss

RSS 主要收录普通文章,不收录 article: false 的指南、目录和工具页。

sitemap ​

docs/.vitepress/config.ts 配置了 sitemap.hostname,构建后生成:

text
docs/.vitepress/dist/sitemap.xml

线上地址是:

text
https://www.baecon.cn/sitemap.xml

配置会过滤掉指定的 noindex 工具页,例如搜索页、留言页、友链页、导航页和风险链接页。不要手工编辑 sitemap.xml。

第 6 步:不要修改 dist ​

docs/.vitepress/dist/ 是构建输出,不是源码:

  • 下次 pnpm docs:build 会覆盖或重新生成;
  • dist 通常被 .gitignore 忽略;
  • CNB 部署的是它自己重新构建出来的 dist;
  • 你手工修复 dist 不会进入源码,也不会被后续部署保留。

需要改页面就改 docs/ 下的源文件;需要改图片就改 docs/public/ 下的源图片。

生产构建常见错误 ​

现象常见原因处理
编译中途退出frontmatter、Markdown 或代码语法错误查看第一条错误和出错文件
Pagefind 没有生成构建未真正完成,或搜索插件报错重新构建并查看完整日志
heap out of memory构建进程内存不足关闭占内存程序后重试;不要随意删构建脚本里的内存参数
构建成功但页面空白模板、组件或配置问题用 pnpm docs:preview 检查,再看浏览器控制台
修改 dist 后线上没变化改的是构建产物,不是源码改源文件并重新构建、提交、推送

上线前 SEO 审计 ​

第 1 步:确认已经构建 ​

审计脚本 scripts/audit-site.mjs 读取:

text
docs/.vitepress/dist/

所以必须先:

bash
pnpm docs:build

再:

bash
pnpm docs:audit

如果 dist 不存在或还是旧版本,审计要么读取失败,要么检查旧页面。审计不能代替构建。

第 2 步:运行审计 ​

bash
pnpm docs:audit

本仓库当前一次实际输出是(页面数会随内容变化):

text
SEO 审计:检查 34 个 HTML 页面,sitemap 29 个 URL

结果:未发现阻塞性 SEO 错误。

34 是除 404.html 外参与检查的 HTML 页面数;29 是 sitemap 中的 URL 数。两个数字不是固定的质量指标,新增文章、目录页、指南页,或配置 noindex 页面,都会让数字变化。

写作指南扩充后,下一次构建可能得到不同页面数;不要为了追求固定的 34/29 去增删页面。

第 3 步:正确解读结果 ​

审计结果分两类:

类型是否阻塞发布含义
错误:是必须修复,否则 CNB 不应继续部署
警告:通常不阻塞退出码,但仍需判断例如可收录页面没有出现在 sitemap

真正决定能否通过的是:脚本是否以 0 退出,以及有没有 错误:。只有 结果:未发现阻塞性 SEO 错误。 才表示没有阻塞项。

如果出现警告,也不要直接忽略。先判断是页面类型、noindex 配置还是 sitemap 过滤造成,再决定是否需要修改。

第 4 步:审计通常检查什么 ​

当前脚本会读取每个 HTML 文件并检查:

  • <title> 是否存在;
  • description 是否存在;
  • canonical 是否存在且指向正式域名;
  • robots 是否存在;
  • Open Graph 的 title 和 description 是否存在;
  • 非 noindex 页面是否恰好有一个 H1;
  • <img> 是否带有 alt 属性;
  • 可收录页面是否出现在 sitemap;
  • noindex 页面是否错误地出现在 sitemap。

其中任何阻塞错误都会让审计失败。注意:ignoreDeadLinks=true 使构建不拦截失效链接;审计不检查图片文件是否存在,空 alt 也可能通过;链接、图片和摘要质量必须人工检查。审计是页面结构检查,不代替人工检查内容是否有错别字、链接是否有意义或手机端是否易读。

第 5 步:出现审计错误时怎么修 ​

按以下顺序处理:

  1. 阅读错误行,找到第一个报错页面;
  2. 看错误是 title、description、canonical、H1、alt 还是 sitemap;
  3. 修改对应 Markdown 的 frontmatter 或正文;
  4. 重新 pnpm docs:build;
  5. 再运行 pnpm docs:audit;
  6. 重复直到没有阻塞错误。

常见对应关系:

审计提示最可能的原因修复方向
人工发现没有 title站点标题兜底可能让审计通过补 frontmatter title,不要只依赖审计
人工发现没有摘要站点描述兜底可能让审计通过补 frontmatter description
h1 数量为 0正文没有 H1添加唯一 H1
h1 数量为 2正文有两个 H1删除一个,改成 H2
缺少 canonical页面头信息生成异常检查 permalink 和站点配置,不要手改 dist
canonical 不是正式域名URL 使用了错误域名或构造异常检查 SITE.url、permalink 和配置
图片缺少 alt 属性Markdown 括号为空或 HTML 图片漏 alt补有意义 alt;空 alt 仍可能通过审计
noindex 页面出现在 sitemap工具页过滤与页面配置不一致修正页面类型或由维护者调整过滤配置

审计常见错误 ​

  • 还没 build 就 audit:先构建;
  • 构建失败后继续 audit:先解决构建错误;
  • 只修改 dist:下次构建就丢;
  • 看到警告就改 sitemap 文件:sitemap 是生成文件;
  • 为了让数字变少而删除正常页面:数字不是目标,结构正确才是目标。

预览生产构建 ​

第 1 步:先完成构建 ​

bash
pnpm docs:build

预览服务器不会替你编译 Markdown。没有 dist 或 dist 很旧,预览到的就是旧内容。

第 2 步:启动预览服务器 ​

bash
pnpm docs:preview

预期终端出现类似:

text
➜  Local:   http://localhost:4173/

打开这个地址,检查真实构建效果。

第 3 步:指定其他预览端口 ​

如果 4173 被占用,可以使用:

bash
pnpm docs:preview -- --port 4174

然后打开:

text
http://localhost:4174/

这里的双横线 -- 表示把后面的参数继续传给 VitePress。不要写成 pnpm docs:preview --port 4174 后期待一定能生效。

第 4 步:理解开发服务器和预览服务器的区别 ​

项目pnpm docs:devpnpm docs:preview
使用源码还是 dist源码,按需编译已生成的 dist
默认端口51744173
HMR有没有
搜索索引开发阶段可能不完整使用构建生成的 Pagefind
适合检查什么写作、布局、交互生产构建、链接、搜索、SEO 结果
修改后是否自动更新通常自动不会重新构建;需要重新 build 并重启预览

预览服务器看到的效果更接近线上,但它仍然不是 EdgeOne。域名、CDN、统计、评论网络等仍要在正式站点验证。

第 5 步:重新构建后重启预览 ​

如果你修改了 Markdown 或配置,正确顺序是:

  1. 在预览终端按 Ctrl+C 停止;
  2. 运行 pnpm docs:build;
  3. 再运行 pnpm docs:preview;
  4. 浏览器刷新并检查新产物。

为什么必须重启?预览服务器面向固定的 dist 和带哈希的资源文件。重新构建后,HTML 可能引用新的资源文件名;继续用旧预览进程或旧页面缓存,容易出现样式丢失、搜索索引过期或看到旧页面。重启是最稳妥的做法。

预览常见错误 ​

现象原因处理
打开 4173 不是最新文章没有重新构建或预览进程还在用旧 distbuild 后重启 preview
搜索还是旧结果Pagefind 索引没有更新重新构建,重启预览,硬刷新
页面没有 HMR预览服务器本来就不支持 HMR开发用 docs:dev,验收用 docs:preview
样式和开发模式不同看到的是生产构建这是正常的,按生产结果检查

提交前检查 Git 变更 ​

Git 是版本控制工具。提交前要确认:只提交文章、图片和必要的源码,不提交构建产物、缓存和临时文件。

第 1 步:查看当前改动 ​

bash
git status --short

常见标记:

标记含义
M已修改的已跟踪文件
A已暂存的新文件
D已删除的已跟踪文件
??尚未被 Git 跟踪的新文件

新手最容易漏掉的是尚未跟踪的图片:git diff --stat 不会显示未跟踪文件,必须看 git status --short。

第 2 步:查看改动规模 ​

bash
git diff --stat

它会显示已跟踪文件改了多少行。新文件不会出现在这里,所以还要看 git status --short。

检查具体文本差异:

bash
git diff -- docs/posts/技术笔记/01.example-article.md

如果文件是全新的,git diff 在暂存前可能没有输出,可以直接在编辑器中复查,或暂存后再看:

bash
git add docs/posts/技术笔记/01.example-article.md
git diff --cached -- docs/posts/技术笔记/01.example-article.md

第 3 步:检查新增图片 ​

先看状态:

bash
git status --short docs/public/images/posts

再列出某个文章目录:

powershell
Get-ChildItem docs\public\images\posts\example-article -File

Git Bash、macOS 或 Linux:

bash
ls docs/public/images/posts/example-article

确认:

  • 图片确实存在;
  • 文件名与 Markdown 中引用完全一致;
  • 没有把本地缩略图、临时截图和重复文件一起带上;
  • 没有误放 C:\Users\... 这样的本地路径;
  • 每张图片都有用途和 alt。

第 4 步:确认不要提交的生成文件 ​

路径来源为什么不要提交
docs/.vitepress/dist/pnpm docs:build构建产物,CNB 会重新生成
docs/.vitepress/cache/VitePress/Vite 缓存本机缓存,体积大且环境相关
docs/public/search-manifest.jsonplugins.ts 启动时由文章目录生成每次会重新生成,手改没有意义
stats.html可选的构建分析报告分析产物,不是站点源码
node_modules/依赖安装可由 lockfile 重建,体积巨大
*.log本地日志临时文件,可能含本机信息

.gitignore 已经忽略这些路径,但不要用 git add -f 强制加入。如果不确定某个文件是否被忽略:

bash
git check-ignore -v docs/.vitepress/dist/index.html

输出说明匹配了哪条忽略规则;没有输出通常表示没有被忽略。

第 5 步:暂存正确的文件 ​

只添加本次发布需要的源码,例如:

bash
git add docs/posts/技术笔记/01.example-article.md
git add docs/public/images/posts/example-article
git add docs/writing-guide/markdown-basics.md
git add docs/writing-guide/publishing.md

如果改了导航或目录页,再按需添加:

bash
git add docs/catalog/技术笔记.md
git add docs/.vitepress/ConfigHyde/Nav.ts

不要为了省事直接:

bash
git add .

除非你已经逐项检查过工作区,否则它可能把无关改动、临时文件或不应提交的图片一起加入。

第 6 步:复查暂存区 ​

bash
git diff --cached --stat
git status --short

预期只看到本次文章相关文件,状态中不应出现 dist、cache、search-manifest 或 stats.html。

Git 检查常见错误 ​

  • 漏提交图片:页面线上 404;
  • 把 dist 一起提交:仓库变大且容易冲突;
  • 把 search-manifest.json 当源码修改:下次启动就被覆盖;
  • 用 git add . 带上了无关文件:发布范围失控;
  • 提交了包含 Token 的 .env 或日志:立即停止推送并按安全流程处理。

提交与推送 ​

第 1 步:确认当前分支 ​

bash
git branch --show-current

预期:

text
main

CNB 的 .cnb.yml 只在推送到 main 时触发发布。如果当前不是 main,不要假设推送后一定自动部署;先确认团队的分支流程。

第 2 步:创建提交 ​

一条清楚的提交信息应该说明改了什么。例如:

bash
git commit -m "docs: add markdown writing guide"

或者:

bash
git commit -m "docs: 新增 Markdown 写作基础指南"

预期看到类似:

text
[main abc1234] docs: add markdown writing guide
 3 files changed, 600 insertions(+)

提交信息不是越长越好,但要能看出这次发布的内容。不要写 update、test、修改 这类无法判断范围的标题。

第 3 步:推送 main 分支 ​

bash
git push origin main

预期看到类似:

text
To <仓库地址>
   abc1234..def5678  main -> main

推送成功只表示代码到了远端仓库,不表示线上已经更新。线上更新要等 CNB 构建和 EdgeOne 部署成功。

第 4 步:确认推送后发生了什么 ​

推送 main 后,CNB 会自动:

  1. 安装依赖;
  2. 重新 docs:build;
  3. 运行 docs:audit;
  4. 部署 dist 到 EdgeOne。

如果本地能构建但 CNB 失败,常见原因是 lockfile、Node 版本、敏感变量缺失,或只在你本机存在但没有提交的文件。

推送常见错误 ​

现象原因处理
nothing to commit没有暂存改动,或已经提交过检查 git status
推送被拒绝远端 main 有新提交先同步远端;不要直接强推
页面在本地有、线上没有文件没提交、图片没提交、CNB 失败或缓存未更新从提交记录和 CNB 日志逐项检查
推送后没有触发 CNB推到了非 main 分支确认目标分支是 main
提交里出现 Token 或密码敏感信息被误加入版本库立即停止,按项目安全流程处理,不要继续公开

如果推送被拒绝,初学者最安全的做法是先询问维护者。熟悉 Git 的人可以按团队约定同步远端后重新提交,但不要使用 git push --force 覆盖别人的 main 分支。

CNB 自动构建与部署 ​

触发器:只有 main 的 push ​

.cnb.yml 的顶层结构是:

yaml
main:
  push:

这表示只有向 main 分支执行 push 时才进入这条流水线。其他分支推送、单纯的本地保存、创建文件但没有提交,都不会自动部署。

流水线运行环境 ​

.cnb.yml 中声明的发布环境包括:

  • runner:16 核 CPU;
  • services:docker 和 git-clone-yyds;
  • Docker 镜像:docker.cnb.cool/znb/images/node:22;
  • 构建缓存:/data/.cache:copy-on-write;
  • 部署阶段使用 node:22 镜像;
  • 环境变量通过 imports 从 CNB 的 secrets 仓库引入。

不要在文章、截图、日志或提交信息里暴露 secrets 内容。真实 Token 只应存在于受控的 CNB 环境变量中。

流水线阶段顺序 ​

.cnb.yml 中的实际阶段按顺序如下:

顺序阶段关键脚本或动作作用
1构建当前项目写入构建时间环境变量记录本次构建信息
2设置淘宝源npm config set registry https://registry.npmmirror.com使用国内镜像加速安装
3打印环境npm install -g pnpm@12.16.1 && node -v && npm -v && yarn -v && pnpm -v固定 pnpm 版本并输出环境版本
4安装依赖pnpm install --frozen-lockfile严格按 lockfile 安装
5编译项目pnpm docs:build生成生产构建和搜索/RSS/sitemap
6SEO Auditpnpm docs:audit检查 SEO,错误会阻止后续部署
7部署到 EdgeOne Makersnpx --yes edgeone@1.6.47 makers deploy ./docs/.vitepress/dist -n my-blog-teek -e production -t $EDGEONE_PAGES_API_TOKEN使用固定 EdgeOne CLI 版本上传 dist
8构建知识库扫描 docs/**/*.md 和 docs/**/*.txtCNB 的额外知识库任务,不是网页发布本身

核心发布命令可以单独理解为:

bash
pnpm install --frozen-lockfile
pnpm docs:build
pnpm docs:audit
npx --yes edgeone@1.6.47 makers deploy ./docs/.vitepress/dist -n my-blog-teek -e production -t $EDGEONE_PAGES_API_TOKEN

为什么审计在部署前 ​

顺序是 build → audit → deploy:

  • build 生成 dist;
  • audit 读取 dist 并检查 SEO;
  • audit 通过后,才部署 dist。

如果 audit 以错误状态退出,正常的 CI 流程不会继续执行后面的部署步骤。这样能避免把 H1 数量错误、缺少 alt 属性、canonical 或 sitemap 不一致的页面发布出去;它不能替代人工检查摘要、链接、图片文件和空 alt。

不要暴露 Token ​

部署命令中的:

text
$EDGEONE_PAGES_API_TOKEN

表示从 CNB 环境中读取变量。不要:

  • 把真实 Token 写进 .cnb.yml;
  • 把 Token 写进 Markdown、README 或代码注释;
  • 在终端执行 echo $EDGEONE_PAGES_API_TOKEN 并截图;
  • 把包含环境变量的完整构建日志公开发布;
  • 在本地创建并提交存放 Token 的文件。

Token 缺失或过期时,部署阶段会失败。正确做法是由有权限的维护者在 CNB 的受控设置中更新或轮换密钥,而不是修改文章内容来绕过。

CNB 常见错误 ​

现象可能原因处理
流水线没有启动不是 push 到 main确认分支和推送成功
ERR_PNPM_OUTDATED_LOCKFILEpackage.json 与 lockfile 不一致恢复正确 lockfile,或由维护者明确处理依赖变更
build 阶段失败源码、frontmatter、依赖或内存问题先在本机复现并修复
audit 阶段失败存在阻塞性 SEO 错误按审计错误修复后重新构建并推送
部署阶段失败Token 缺失/过期、EdgeOne 权限或网络问题联系有权限的维护者检查 secrets 和部署配置
知识库阶段失败知识库扫描或服务问题检查 CNB 日志;它通常在部署之后,不能据此判断网页是否已部署

部署成功的判断标准 ​

看到 CNB 全部核心阶段成功,并且 EdgeOne 显示新的部署版本或部署完成,才可以进入线上验收。仅仅看到 git push 成功不算发布完成。

上线后验收 ​

线上验收必须打开正式域名,不要用 localhost:

text
https://www.baecon.cn/

第 1 步:确认部署版本 ​

  1. 打开 CNB 本次构建记录;
  2. 确认 安装依赖、编译项目、SEO Audit、部署到 EdgeOne Makers 都成功;
  3. 打开 EdgeOne 控制台,确认最新部署版本存在;
  4. 用无痕窗口打开首页,避免本地缓存干扰。

第 2 步:检查首页文章卡片 ​

打开:

text
https://www.baecon.cn/

检查新文章是否出现在预期位置:

  • 标题正确;
  • description 摘要合理;
  • 封面图显示,不失真或 404;
  • 日期、分类、标签正确;
  • 点击卡片能进入文章详情;
  • 精选文章只有在设置 top: 1 等标记后才进入精选区,不要把所有普通文章都当作精选。

第 3 步:检查文章详情 ​

打开新文章的 permalink,例如:

text
https://www.baecon.cn/posts/技术笔记/example-article

逐项检查:

  • 地址不带 .html;
  • 页面只有一个 H1;
  • H2/H3 层级和右侧目录正常;
  • 正文、图片、alt、图注正常;
  • 代码块有语言标签、行号、复制按钮;
  • 代码组和时间线没有错位;
  • 文章信息区显示日期、分类、标签、字数、阅读时长和更新时间;
  • 浏览量等 Umami 数据只在正式域名上产生,不要在本地判断线上统计。

第 4 步:检查目录页和侧边栏 ​

打开顶部导航中的目录入口,例如:

text
https://www.baecon.cn/catalog/技术笔记

检查:

  • 新文章出现在目录页;
  • 目录页不显示左侧栏、评论,也不进入搜索;
  • 文章详情页的左侧栏能找到新文章;
  • 点击侧边栏项目能正确跳转;
  • 修改或新增目录页后,如果本地开发环境没有刷新,先重启开发服务器。

第 5 步:检查搜索 ​

在正式站点点击搜索,输入新文章标题中的独特词或正文中的独特短语。

检查:

  • 能搜到 pagefind-indexed: true 的新文章;
  • 搜索结果标题和链接正确;
  • 点击结果能进入正确 route;
  • 写作指南、目录页和工具页按当前配置不进入搜索是预期行为;
  • 如果搜不到,先重新 pnpm docs:build,再重启预览并硬刷新。

第 6 步:检查评论 ​

打开新文章底部评论区:

  • 文章应设置 comment: true;
  • 目录页和写作指南使用 comment: false,不显示评论是预期行为;
  • 评论框能加载,提交测试评论前先确认不会污染正式讨论;
  • 如果评论加载失败,打开浏览器开发者工具的 Network 面板,检查 Twikoo 外部请求是否被拦截;
  • 评论组件依赖外部 Twikoo 服务,网络或第三方服务异常不是 Markdown 构建错误。

评论测试不要提交垃圾内容。测试完成后按实际权限清理。

第 7 步:检查分类、标签和归档 ​

打开:

text
https://www.baecon.cn/categories
https://www.baecon.cn/tags
https://www.baecon.cn/archives

检查:

  • 新文章进入正确的分类;
  • 标签列表包含文章的标签;
  • 日期归档正确;
  • 从这些页面点击进入文章时链接有效;
  • 没有重复文章或错误分类;
  • 目录页和写作指南不进入这些文章聚合页,这是按文章类型区分的预期行为。

第 8 步:检查 RSS 和 sitemap ​

打开:

text
https://www.baecon.cn/feed.rss
https://www.baecon.cn/sitemap.xml

检查:

  • feed.rss 能打开并包含新文章;
  • RSS 中的链接是正式域名和正确 permalink;
  • sitemap.xml 包含新文章;
  • sitemap 不包含配置过滤掉的无索引工具页;
  • 文件内容不是本地 dist 里的旧时间或旧 URL。

第 9 步:检查 canonical ​

在文章页按 Ctrl+U 查看源代码,或打开开发者工具的 Elements 面板,搜索:

html
<link rel="canonical" href="...">

源码中的中文路径通常会被百分号编码,浏览器地址栏和搜索引擎会解码显示。不要因为看到 %E6%8A%80... 就误判为错误。下面是解码后的可读形式:

html
<link rel="canonical" href="https://www.baecon.cn/posts/技术笔记/example-article">

检查:

  • 使用 https://www.baecon.cn 正式域名;
  • 使用 permalink 对应的路径;
  • 没有 .html;
  • 没有 localhost;
  • 没有重复的 canonical;
  • 分享页、搜索页等工具页的 noindex 设置符合配置。

第 10 步:检查移动端 ​

使用浏览器开发者工具的设备模拟,或直接用手机访问正式站点,检查:

  • 文章正文没有横向滚动;
  • 代码块可以水平和垂直滚动;
  • 表格没有把整个页面撑破;
  • 图片自适应宽度;
  • 侧边栏和导航可以打开、关闭;
  • 搜索框可用;
  • 评论区不遮挡内容;
  • 长标题不会溢出。

第 11 步:检查文章元数据 ​

检查页面 H1 下方或文章底部区域:

  • 标题;
  • 创建日期;
  • 更新时间;
  • 分类;
  • 标签;
  • 字数;
  • 阅读时长;
  • 浏览量;
  • 分享按钮。

「最后更新于」来自构建系统的更新时间信息;「浏览量」来自 Umami 公共接口,本地环境和未部署版本不要期待有正式数据。

第 12 步:检查 404 ​

访问一个不存在的正式 URL,例如:

text
https://www.baecon.cn/this-page-should-not-exist-20261108

检查:

  • 显示站点自己的 404 页面;
  • 不会把不存在的路径错误地显示成首页正文;
  • 顶部导航仍可使用;
  • 不会出现构建错误堆栈或敏感信息。

删除旧文章后,旧 URL 默认也不会自动跳到新文章。需要重定向时必须由站点维护者在主机或 CDN 层配置。

上线验收常见错误 ​

错误结果正确处理
用 localhost 验收看不到正式域名、CDN、统计和评论状态使用 https://www.baecon.cn
只检查首页文章详情、搜索、侧栏、RSS 可能仍有问题按本节逐项检查
看到首页旧卡片就判定失败可能仍处于 CDN/浏览器缓存先确认部署成功,再清缓存或硬刷新
把目录页当成文章目录页本来不显示评论、不进搜索和首页卡片按页面类型判断预期行为

清理 EdgeOne 缓存与强制刷新(可选) ​

部署成功后,大多数情况下新版本会自动生效。如果你确认 CNB 和 EdgeOne 都已成功,但浏览器仍看到旧页面,才进行这一步。

第 1 步:区分两种缓存 ​

缓存位置清除方式
浏览器缓存你的电脑或手机硬刷新、无痕窗口、清除站点数据
EdgeOne CDN 缓存云边缘节点在 EdgeOne 控制台刷新 URL 或目录

强制刷新浏览器不会清除 EdgeOne 的 CDN 缓存;反过来,刷新 CDN 也不会自动清掉你手机里的浏览器缓存。

第 2 步:在 EdgeOne 控制台刷新 ​

如果确认是 CDN 旧版本:

  1. 登录 EdgeOne 控制台;
  2. 找到 my-blog-teek 对应的站点或部署项目;
  3. 查找缓存刷新、刷新 URL、目录刷新或版本部署相关入口;
  4. 优先只刷新问题 URL;不确定影响范围时再刷新全站;
  5. 等待刷新任务完成。

控制台的具体菜单名称可能随平台版本变化,以实际界面为准。不要为了找按钮去修改源码或删除 dist。

第 3 步:浏览器硬刷新 ​

Windows 常用:

text
Ctrl+F5

macOS 常用:

text
Cmd+Shift+R

仍然怀疑缓存时,使用无痕窗口或直接换一个浏览器测试。手机端可以关闭页面、清理站点数据后再打开。

什么时候不需要刷新缓存 ​

  • 部署尚未完成;
  • CNB 日志显示构建或审计失败;
  • 页面本来就没有提交到 Git;
  • 图片文件根本没有上传;
  • 路由本身写错。

这些情况下刷新缓存不会修好问题,应先修复源头并重新部署。

回滚与误删恢复 ​

回滚是把线上恢复到之前可用状态。先判断问题属于「源码内容问题」还是「部署产物问题」,再选择方式。

方式一:用 git revert 撤销某次提交 ​

适用场景:某篇文章、某次配置修改导致了内容错误,需要从源码层恢复。

步骤:

  1. 查看最近的提交:
bash
git log --oneline -5
  1. 找到要撤销的提交短哈希,例如 abc1234:
bash
git revert abc1234
  1. Git 会创建一个新的 revert 提交。若提示冲突,按冲突文件逐项解决,不要盲目删除文件。
  2. 检查工作区:
bash
git status --short
git log --oneline -3
  1. 推送 main:
bash
git push origin main
  1. 等待 CNB 重新构建和 EdgeOne 部署,再按上线验收清单检查。

为什么用 git revert?它保留历史,并生成一个可审计的新提交,适合多人共享的 main 分支。不要习惯性使用:

bash
git reset --hard
git push --force

这些命令会改写历史或覆盖远端,对共享分支风险很高。

方式二:使用 EdgeOne 的部署版本回滚 ​

适用场景:源码大致正确,但当前静态产物出现紧急问题,需要快速回到上一版网站。

如果 EdgeOne 控制台提供部署历史或版本回滚:

  1. 登录 EdgeOne 控制台;
  2. 找到 my-blog-teek 项目;
  3. 查看部署历史;
  4. 选择上一个已知正常的版本进行回滚;
  5. 检查正式域名。

注意:

  • 版本回滚只改变线上静态产物,不会改变 Git 源码;
  • 下一次有人推送 main 并部署时,网站可能再次变成当前源码的新版本;
  • 不同平台和历史版本的实际可用性不同,界面没有该能力时不要假设一定有。

Markdown 删除不会自动回滚 ​

删除一篇文章并推送 main 后,构建会生成一个不再包含该文章的新版本。结果是:

  • 新构建中该 route 消失;
  • 旧 URL 通常显示 404;
  • sitemap 和 RSS 会在新构建中更新;
  • 如果 CDN 或浏览器还有缓存,短时间内可能仍看到旧页面;
  • 不会自动把旧 URL 重定向到另一篇文章;
  • 不会自动恢复被删除的 Markdown。

要恢复被误删的文章,用 git revert 撤销删除提交,或从 Git 历史找回文件后重新提交。要永久废弃一个 URL 并跳转到新地址,需要维护者在主机/CDN 层配置重定向;当前 Markdown 写作流程没有自动重定向机制。

回滚常见错误 ​

错误风险正确做法
在 main 上 reset --hard 后强推覆盖别人的提交,可能造成不可恢复的协作事故用 git revert
只回滚 EdgeOne,不修 Git下次部署旧问题会回来同时修复源码并提交
删除 Markdown 后期望自动恢复新版本会正常地移除页面从 Git 历史恢复
删除后不检查旧 URL访客可能遇到 404配置重定向或保留替代页面
回滚后不清缓存就检查可能仍看到回滚前的页面确认部署完成,必要时刷新 CDN 和浏览器缓存

常见问题与故障排查 ​

遇到问题时,先判断故障发生在哪个阶段:

text
Markdown/frontmatter
→ 本地开发服务器
→ 生产构建
→ SEO 审计
→ 预览
→ Git
→ CNB
→ EdgeOne
→ 线上浏览器/CDN

不要一上来就删除 cache、dist 或 fonts。先看终端第一条错误、CNB 第一个失败阶段和浏览器 Network 面板,通常能更快定位。

快速定位表 ​

症状优先检查
页面顶部出现 YAML 文本或构建报 YAML 错误frontmatter 起止线和缩进
审计提示 h1 数量错误正文 H1 是否恰好一个
图片 404docs/public/images/posts/... 与 /images/posts/... 是否对应
图片无 altMarkdown 图片方括号是否为空
文章不进侧边栏sidebar、文件位置、是否重启(article 不直接控制侧栏)
文章不进目录页path、inCatalogue: false、目录扫描是否重启
搜不到文章pagefind-indexed、是否重新 build
首页不显示卡片article、目录、permalink、构建
评论不显示comment、页面类型、外部 Twikoo 请求
线上仍是旧页面部署是否成功、CDN/浏览器缓存
本地正常、CNB 失败lockfile、Node 版本、未提交文件、secrets
本地没有 Umami 数据统计只在正式域名运行,这是设计行为

1. YAML / frontmatter 报错 ​

典型表现:

  • 构建直接失败,并指向某个 .md 文件;
  • 页面顶部显示了 title:、description: 等原始文本;
  • 页面布局、标题或摘要没有按预期生效。

为什么会发生:frontmatter 位于 Markdown 文件最顶部,必须使用严格的 YAML 语法。多一个分隔线、缩进错误、用 Tab、键值中有未转义的冒号,都会让解析失败或让字段失效。

逐步排查:

  1. 打开报错文件,确认第一行是 ---,不是空行或 H1;
  2. 确认 frontmatter 内部还有且只有一个结束行 ---;
  3. 确认结束行后面空一行,再写 # 正文 H1;
  4. 检查键值冒号后面是否有空格;
  5. 多行数组使用两个空格缩进;
  6. 值里包含 冒号+空格 时,用英文双引号包住整个值;
  7. 保存后重新运行 pnpm docs:build。

正确示例:

yaml
---
title: Markdown 写作基础
description: "前提: 已安装 Node.js 和 pnpm。"
permalink: /posts/技术笔记/markdown-basics
categories:
  - 技术笔记
tags:
  - Markdown
  - VitePress
article: true
sidebar: true
pagefind-indexed: true
comment: true
---

错误示例:

yaml
---
title: Markdown 写作基础
description: 前提: 已安装 Node.js 和 pnpm。
---

---

# Markdown 写作基础

这里同时有两个问题:description 的值里有未加引号的冒号空格,正文前又多了一组分隔线。

常见错误:

  • 在 frontmatter 后面又复制了一遍 frontmatter;
  • 把 --- 写成了 -- 或 ...;
  • YAML 列表缩进不一致;
  • 从网页复制了看不见的特殊引号;
  • 把 H1 写在 frontmatter 前面。

如果错误信息没有明确指出文件,先看终端中最后出现的 Markdown 路径,再从那个文件开始检查。

2. 缺少或重复 H1,导致审计失败 ​

典型表现:pnpm docs:audit 出现类似:

text
/posts/技术笔记/example-article: h1 数量为 0

或:

text
/posts/技术笔记/example-article: h1 数量为 2

为什么重要:H1 是页面唯一主标题。VitePress 的 frontmatter title 不是正文 HTML 的 H1;布局页也不会因为写了 layout: page 就自动免除 H1 检查。

逐步排查:

  1. 在文章正文中查找以单个 # 开头的行;
  2. 确保只有一个这样的行;
  3. 如果出现多个,把次要标题改成 ## 或 ###;
  4. 如果没有,在 frontmatter 结束后空一行,添加唯一 H1;
  5. 重新构建并审计。

可先列出候选行:

bash
git grep -n '^# ' -- docs/posts

注意:这个命令也会匹配代码块里的 # 注释或示例标题,不能只看命令结果就机械删除。最终以页面正文中真正被解析的 H1 为准。

目录页、写作指南页同样需要 H1。pagefind-indexed: false 只排除搜索,不会让 SEO 审计跳过 H1 检查。

3. 图片 404 或缺少 alt ​

图片 404 ​

先确认磁盘文件是否存在:

powershell
Test-Path docs\public\images\posts\example-article\editor-preview.webp

预期:

text
True

如果返回 False,说明文件不在以为的位置,或者文件名/扩展名不一致。

然后检查 Markdown 引用:

markdown
![编辑器预览](/images/posts/example-article/editor-preview.webp)

正确映射关系:

text
磁盘:docs/public/images/posts/example-article/editor-preview.webp
URL: /images/posts/example-article/editor-preview.webp

常见原因:

  • Markdown 写成了 docs/public/images/...;
  • 使用了 C:\Users\...;
  • 把图片放进了 docs/posts/;
  • 文件名大小写不一致;
  • 实际是 .png,链接写成 .webp;
  • 文件名有空格或中文,URL 与实际文件不一致;
  • 图片目录没有提交到 Git。

缺少 alt ​

审计会报告类似:

text
/posts/...: 1 张图片缺少 alt

Markdown 图片的标准格式是:

markdown
![描述图片内容的文字](/images/posts/example-article/editor-preview.webp)

方括号里必须有具体描述。不要只写 ![](路径),也不要用图片、截图这种空泛内容敷衍。手写 <img> 时同样必须写 alt。

本地检查顺序 ​

  1. 用 Test-Path 确认磁盘文件;
  2. 直接用 http://localhost:5174/images/posts/... 打开图片;
  3. 打不开时检查路径映射;
  4. 图片能打开但页面不显示时检查 Markdown 语法和浏览器缓存;
  5. 重新 build 后运行 audit 检查 alt 属性,并在浏览器确认图片实际加载、alt 有意义。

4. 页面没有出现在侧边栏、目录页、搜索或首页 ​

这几个区域由不同机制生成,不要用一个检查结果推断全部。

区域数据来源必要条件刷新方式
文章左侧栏docs/.vitepress/sidebar.ts 扫描 docs/posts文件在 posts 下,sidebar 不为 false;当前扫描器不读取 article修改目录或配置后重启 dev
目录页Teek 的 catalogue: true 和 path 扫描path 指向实际文章目录,文章未设置 inCatalogue: false新增/删除文章或目录页后重启 dev
Pagefind 搜索构建阶段的搜索索引pagefind-indexed: true,重新 build重新 build 并重启 preview
首页文章卡片文章集合和文章元数据位于 posts、article: true、permalink 有效重新构建/刷新
分类/标签/归档文章 frontmatter 与目录文章类型、分类、标签、日期有效重新构建
RSSRSS 插件过滤article 不为 false,非指南目录重新 build

逐步检查:

  1. 文件是否在 docs/posts/<分类>/... 下,而不是 docs/writing-guide/ 或 docs/catalog/;
  2. frontmatter 是否写了 article: true;
  3. 文章左侧栏是否写了 sidebar: true;
  4. 搜索是否写了 pagefind-indexed: true;
  5. permalink 是否以 /posts/ 开头且唯一;
  6. 新增或删除文件、目录后,是否重启了开发服务器;
  7. 测试搜索前是否执行了最新构建;
  8. 目录页的 path 是否真的指向文章所在的相对目录。

写作指南、目录页和工具页使用 article: false、pagefind-indexed: false,它们本来就不会进入首页文章卡片和搜索,不应按普通文章判断。

5. Pagefind 搜索索引过期,或预览仍是旧资源 ​

典型表现:

  • 新文章已经提交,但搜索不到;
  • 搜索能搜到旧标题;
  • 预览页面还是修改前的样式或图片;
  • 浏览器里引用旧哈希资源,出现样式错乱。

为什么:Pagefind 索引在 pnpm docs:build 阶段生成;预览服务器服务的是已有 dist。只改 Markdown 不重新 build,或只 build 不重启旧的预览服务器,都可能看到旧结果。

正确处理顺序:

  1. 停止正在运行的预览或开发服务器:Ctrl+C;
  2. 确认文章 frontmatter 有 pagefind-indexed: true;
  3. 重新构建:
bash
pnpm docs:build
  1. 确认 docs/.vitepress/dist/pagefind/ 已更新;
  2. 重启预览:
bash
pnpm docs:preview
  1. 用无痕窗口打开或执行硬刷新;
  2. 搜索一个只在新文章里出现的独特词。

常见错误:

  • 在开发页面里测试搜索,却以为开发服务器一定生成完整 Pagefind;
  • 改了 dist 里的搜索结果文件,而没有重新 build;
  • 把 pagefind-indexed: false 的指南页当成应该能被搜索的文章;
  • 只刷新浏览器,不重启旧预览进程。

6. 目录页内容要重启开发服务器才刷新 ​

典型表现:新增文章后,文章详情页已经能打开,但 /catalog/... 目录页仍看不到它;重启 pnpm docs:dev 后才出现。

为什么:Teek 的目录页根据 catalogue: true 和 path 扫描文章目录。这个扫描在开发服务器启动或配置加载阶段完成,不是每个 Markdown 文件的 HMR 更新范围。

处理步骤:

  1. 在开发终端按 Ctrl+C;
  2. 重新启动:
bash
pnpm docs:dev
  1. 打开目录页刷新确认;
  2. 如果仍不显示,检查目录页 path 是否准确指向 docs/posts 下的目录;
  3. 检查文章是否设置了 inCatalogue: false,或是否被放在忽略的 _ 开头目录;article: false 本身不会从目录页隐藏。

这是当前项目的预期行为,不是需要改 dist 才能修复的 bug。提交前可以在重启后的目录页里确认新文章已被扫描到。

7. 端口被占用 ​

默认端口:

  • 开发服务器:5174;
  • 预览服务器:4173。

开发配置中 strictPort: false,端口被占用时 Vite 可能自动使用下一个可用端口。因此第一件事是看终端实际打印的 Local: 地址,而不是继续打开旧端口。

处理方式一:使用自动选择的端口

看终端:

text
➜  Local:   http://localhost:5175/

就打开 5175。

处理方式二:明确指定新端口

开发:

bash
pnpm docs:dev -- --port 5175

预览:

bash
pnpm docs:preview -- --port 4174

处理方式三:找出占用端口的进程

Windows PowerShell:

powershell
netstat -ano | findstr :5174

输出最后一列是 PID。确认那是你自己的旧进程后,可以:

powershell
taskkill /PID <PID> /F

把 <PID> 换成实际数字。不要在不认识进程时随意结束系统服务。

Git Bash、macOS 或 Linux 可以使用:

bash
lsof -i :5174

常见错误:

  • 终端已经换到 5175,却一直打开 5174;
  • 同时启动多个 dev 或 preview,忘记旧的还在运行;
  • 用 --port 时少写了传给 pnpm 的 --;
  • 为清端口直接重启电脑,实际上只需结束自己的旧进程。

8. 构建失败 ​

构建失败时不要先改 dist,也不要删除 fonts。按照「第一条错误 → 第一个失败文件 → 最小修改 → 重新构建」处理。

逐步排查:

  1. 向上滚动终端,找到第一条 error 或最开始的失败位置;
  2. 确认 Node.js 版本:
bash
node -v
  1. 确认 pnpm 和依赖:
bash
pnpm -v
pnpm install --frozen-lockfile
  1. 检查报错 Markdown 的 frontmatter、未闭合代码块、容器和时间线;
  2. 检查是否存在重复/错误 permalink;
  3. 确认没有修改 docs/public/font/TsukuARdGothicStd-Bold.woff2 和字体配置;
  4. 重新构建:
bash
pnpm docs:build

常见原因:

原因表现处理
Node.js 版本过低Vite 启动失败或 engine 错误升级到 Node 22 LTS
依赖未安装找不到 vitepress 或插件pnpm install
lockfile 不一致frozen-lockfile 失败恢复 lockfile 或由维护者处理依赖变更
frontmatter/YAML 错误解析失败并指向 Markdown修 frontmatter
围栏代码块未闭合后续正文被当成代码检查反引号数量
容器/时间线未闭合页面结构异常补 :::
内存不足heap out of memory关闭占内存程序后重试,不随意改构建脚本
未提交文件本地有图,CNB 看不到提交图片并检查 Git 状态

如果错误信息中包含环境变量、Token 或内部地址,不要把完整日志直接发到公开地方。只截取必要的堆栈和文件名,并对敏感值打码。

9. 评论区不显示 ​

先确认这是不是预期行为:

页面类型当前配置评论
普通文章comment: true应显示
写作指南comment: false、layout: doc不显示
目录页comment: false、layout: page不显示
工具页comment: false不显示

逐步排查:

  1. 检查文章 frontmatter 是否是 comment: true;
  2. 检查文章是否误用了 layout: page 或 article: false;
  3. 刷新页面,尝试无痕窗口;
  4. 打开浏览器开发者工具 Network,搜索 Twikoo 或 comment 相关请求;
  5. 检查请求是否被广告拦截器、网络策略或公司代理阻止;
  6. 检查浏览器 Console 是否有第三方脚本错误;
  7. 如果其他文章能显示,只这篇不能,优先比较 frontmatter;
  8. 如果全站都不能显示,可能是 Twikoo 外部服务或网络问题,联系维护者。

评论来自外部 Twikoo 服务,不是 Markdown 构建的一部分。构建成功不代表评论后端一定可访问。不要把评论服务的私密配置、数据库密钥或管理凭据写进文章或提交到仓库。

permalink 是页面的正式路由。普通文章的 permalink 应该:

  • 以 /posts/ 开头;
  • 不含 .html;
  • 不含 .md;
  • 不写完整域名;
  • 全站唯一;
  • 与内链、canonical、sitemap 中期望的地址一致。

正确:

yaml
permalink: /posts/技术笔记/example-article

错误:

yaml
permalink: /posts/技术笔记/example-article.html
permalink: docs/posts/技术笔记/example-article
permalink: https://www.baecon.cn/posts/技术笔记/example-article

检查重复:

bash
git grep -n '^permalink:' -- docs/posts

也可以只输出重复项(PowerShell):

powershell
git grep -h '^permalink:' -- docs/posts | Group-Object | Where-Object Count -gt 1 | Select-Object Name,Count

如果看到同一个 route 出现两次,找到两个源文件,修改其中一个。不要通过修改 dist 或 sitemap 绕过。

为什么重要:

  • 侧边栏、搜索清单和目录页可能按 permalink 生成链接;
  • 博客文章路由和 canonical 前缀依赖正确 permalink;
  • 重复 permalink 会导致路由冲突或错误覆盖;
  • 修改 permalink 会改变文章 URL,旧 URL 不会自动重定向。

修改 permalink 后,重新运行:

bash
pnpm docs:build
pnpm docs:audit

并检查预览中的新地址、首页卡片、侧边栏、搜索和 canonical。

11. 删除文章后旧 URL 还在,或变成 404 ​

这是两个不同现象。

旧 URL 仍能打开:常见原因是 CDN 或浏览器缓存,不一定是文章还在构建产物里。先确认:

  1. 源文件确实已从 docs/posts/ 删除;
  2. 删除已提交并推送到 main;
  3. CNB 构建和 EdgeOne 部署已成功;
  4. 新构建的 dist 和 sitemap 不再包含该页面;
  5. 再检查 EdgeOne 缓存和浏览器缓存。

旧 URL 变成 404:如果文章被删除,新部署不再生成对应 HTML,旧 URL 默认就会 404。这是静态站点的正常结果,不是自动错误。

当前项目没有在 Markdown 层配置自动重定向机制。若希望旧 URL 跳到新文章:

  • 需要维护者在 EdgeOne/CDN 或托管平台配置重定向;
  • 需要确认重定向规则优先级和缓存行为;
  • 仅在文章里写一个链接不能替代 HTTP 重定向;
  • 也不要依赖 404.html 自动完成跳转,它只是自定义 404 页面。

删除文章后的正确验收顺序:

  1. 打开旧 URL,确认最终状态符合预期(404 或配置好的重定向);
  2. 打开新 URL(如果文章是移动而不是删除);
  3. 检查 sitemap 已移除旧 URL;
  4. 检查 RSS 已更新;
  5. 清 CDN/浏览器缓存后再次确认;
  6. 检查站内是否还有指向旧 URL 的链接。

12. Umami 只有正式域名数据,本地统计被排除 ​

典型表现:本地 http://localhost:5174 或预览端口能看到页面,但 Umami 后台没有对应访问数据;文章浏览量在本地显示为 0 或不显示。

为什么:统计分析脚本通过 data-domains 限制在正式域名运行。当前配置的站点地址是:

text
https://www.baecon.cn

统计允许的域名是:

text
www.baecon.cn,baecon.cn

localhost、127.0.0.1 和局域网 IP 不在允许列表中,所以本地访问不会写入正式统计。这是为了避免开发数据污染线上数据。

此外:

  • 浏览器开启 Do Not Track 时,Umami 会尊重该设置;
  • 广告拦截器、隐私插件或网络策略可能拦截统计脚本;
  • 页面浏览量是异步读取的正式统计数据,本地没有数据是预期行为;
  • 构建成功不代表统计接口一定被允许访问。

不要这样修:

  • 为了在本地看到统计,随意把 localhost 加入正式统计域名;
  • 修改 docs/.vitepress/site.ts 的正式站点地址;
  • 用本地测试数据判断线上文章热度;
  • 把 Umami Website ID、接口地址或管理凭据当成文章内容发布。

正确验证:

  1. 确认文章已经部署到正式域名;
  2. 用普通浏览器访问正式文章,确认没有被拦截;
  3. 在 Umami 后台查看是否出现该路径;
  4. 如果正式域名也没有数据,再检查统计脚本请求、域名配置和隐私设置。

13. 字体文件不能修改 ​

这是本项目的硬性约束:

text
docs/public/font/TsukuARdGothicStd-Bold.woff2

docs/.vitepress/ConfigHyde/Head.ts 中对它做了预加载:

html
<link rel="preload" href="/font/TsukuARdGothicStd-Bold.woff2" as="font" type="font/woff2" crossorigin="">

因此不要:

  • 修改这个字体文件;
  • 重命名或删除它;
  • 用其他字体替换它;
  • 做字体子集化、压缩或格式转换;
  • 修改字体预加载路径来顺便优化;
  • 为了修复构建问题删除 font 目录。

即使页面看起来字体不对,也不要先动字体文件。先检查 CSS、主题配置、浏览器缓存和构建日志;确实需要调整时,由了解项目约束的维护者处理。

提交前可以检查字体是否被误改:

bash
git status --short docs/public/font

正常情况下这里不应出现你本次文章发布产生的字体改动。

最终发布检查清单 ​

下面的 ☐ 是普通 Unicode 方框,不是可点击控件。复制到任务工具时,可以改成 - [ ]。

环境与本地检查 ​

  • ☐ 当前目录是仓库根目录;
  • ☐ node -v 满足 ^20.19.0 || >=22.12.0,推荐 Node 22 LTS;
  • ☐ pnpm -v 正常;
  • ☐ 已执行 pnpm install 或 pnpm install --frozen-lockfile;
  • ☐ pnpm docs:dev 能启动并打开正确 permalink;
  • ☐ 正文 H1 恰好一个;
  • ☐ frontmatter 只有一个区块,且从第一行开始;
  • ☐ 图片路径在 docs/public/images/posts/<article-slug>/;
  • ☐ 图片引用从 /images/posts/<article-slug>/ 开始;
  • ☐ 每张图片都有有意义 alt;
  • ☐ 站内链接没有 .html、.md、docs/ 或 localhost;
  • ☐ 代码块都有语言标签;
  • ☐ 容器和时间线都正确闭合;
  • ☐ 没有依赖未启用的 Mermaid 或 KaTeX。

构建、审计与预览 ​

  • ☐ 已执行 pnpm docs:build 并以成功状态结束;
  • ☐ docs/.vitepress/dist/ 已生成;
  • ☐ dist/pagefind/ 已生成;
  • ☐ dist/feed.rss 和 dist/sitemap.xml 已生成;
  • ☐ 构建后执行了 pnpm docs:audit;
  • ☐ 审计没有阻塞性错误;
  • ☐ 理解 34/29 这类页面数量会随新增页面变化,不是固定阈值;
  • ☐ 已执行 pnpm docs:preview;
  • ☐ 预览中检查了页面、图片、代码、搜索和链接;
  • ☐ 修改后重新 build 并重启了 preview;
  • ☐ 没有直接编辑 dist。

Git 与 CNB ​

  • ☐ git status --short 已检查;
  • ☐ git diff --stat 已检查;
  • ☐ 新增图片已经出现在未跟踪或已暂存列表中;
  • ☐ 没有提交 docs/.vitepress/dist/;
  • ☐ 没有提交 docs/.vitepress/cache/;
  • ☐ 没有提交 docs/public/search-manifest.json;
  • ☐ 没有提交 stats.html;
  • ☐ 没有提交 node_modules/ 和临时日志;
  • ☐ 提交里没有 Token、密码或私密配置;
  • ☐ 当前分支是 main;
  • ☐ 已执行 git push origin main;
  • ☐ CNB 的安装依赖、构建、SEO Audit 和 EdgeOne 部署阶段成功;
  • ☐ 没有把 $EDGEONE_PAGES_API_TOKEN 写进源码或公开日志。

线上验收 ​

  • ☐ 首页文章卡片显示正确;
  • ☐ 文章详情页可打开,URL 不带 .html;
  • ☐ 目录页能看到新文章;
  • ☐ 文章侧边栏链接正确;
  • ☐ 站内搜索能搜到应被索引的文章;
  • ☐ 评论区符合页面类型和 comment 配置;
  • ☐ /categories、/tags、/archives 正常;
  • ☐ /feed.rss 包含新文章;
  • ☐ /sitemap.xml 包含正确 URL 且不含错误页面;
  • ☐ canonical 指向 https://www.baecon.cn 和正确 permalink;中文可能显示为百分号编码,解码后应一致;
  • ☐ 手机端布局正常;
  • ☐ 文章元数据(日期、分类、标签、字数、阅读时长、更新时间)正常;
  • ☐ 随机不存在 URL 能显示 404;
  • ☐ 如仍有旧页面,已确认部署成功后再刷新 EdgeOne 缓存和浏览器缓存;
  • ☐ 如需回滚,使用 git revert 或 EdgeOne 版本回滚,没有强推 main;
  • ☐ 已确认删除 Markdown 不会自动恢复文章,也不会自动生成重定向;
  • ☐ 已确认本地没有 Umami 正式统计数据是预期行为;
  • ☐ 已确认没有修改 docs/public/font/TsukuARdGothicStd-Bold.woff2。

全部勾选后,这次发布才算完成。

最后更新于: