Skip to content
速览
  • 原判断:半天搞定。实际:三个晚上,一半时间跟博客本身无关。
  • 三个坑没有一个是技术难题,全是最开始的判断错了方向。
  • 三次都先怪外部——缓存、网络、服务,最后发现是自己没看清。
  • 真正要写的编辑器代码反而最顺,因为没引第三方库。

起因 ​

前两篇讲了这个博客是什么、打算写什么。这篇讲它是怎么做出来的。

我原来的判断是:一个静态博客,本质就是一堆 Markdown 文件加一个模板,半天能搞定。结果花了三个晚上,其中一半时间在排查跟博客本身无关的事。

技术栈定了不到十分钟 ​

项选择理由
框架VitePress文档全、配置短、不用写页面
托管GitHub Pages免费,还能挂 HTTPS
发布GitHub Actions推上去自动构建,不用本地打包上传

选型没什么好纠结的。真正的麻烦在后面。

最后跑通的链路长这样 ​

一次发布,两条走法本地编辑器改文章、存文件提交git commit推送git pushGitHub 仓库代码放这儿自动构建GitHub Actions线上页面GitHub Pages推送失败就走这条直接用 Git API 建提交,更稳实线=正常路径  虚线=出问题时的备用路径

先把结果放这儿,下面三个坑都摔在这条链路上。注意虚线那一段:如果不是被坑过一晚上,不会有它。

第一个坑:文章列表全是空的 ​

首页搭好,样式也调完了,打开一看——文章卡片是空的。框在,标题、日期、摘要一个都不显示。

第一反应是数据没加载出来,可能构建缓存的问题。清缓存,重启,还是一样。

第二步去看构建产物里的 HTML,发现卡片的结构是渲染出来的,链接也在,就是字段全空。

第三步才找到原因:我用了一个新版本才有的接口来读取文章信息,而这个版本的代码里根本没有这个参数。它不报错,也不警告,直接当没看见。

js
// docs/.vitepress/posts.data.mjs
export default createContentLoader('posts/*.md', {
  transformData(raw) { /* 以为这样能读出文章信息,其实参数不存在 */ } 
  transform(raw)     { /* 这个版本真正支持的写法 */ }                 
  excerpt: true
})

改成下面那种写法就好了。

不报错不等于成功了

有些失败是静默的,它只是安静地什么都不做。找这种问题,别从"哪里报错了"入手,要从"哪一步的结果是空的"往回倒推。

第二个坑:推送一直卡住不动 ​

代码写完了要推到 GitHub。命令行敲下 push,光标转啊转,等了十分钟,一个字都没输出。

先怀疑是网络慢,重试了三次,都一样。

然后怀疑是仓库配错了,检查远程地址,没问题。

最后挨个测端口,发现环境变量里配了一个代理,那个代理是死的。所有走它的请求都被挂住。换成能用的那个,一秒就推上去了。

不过我的问题没那么快结束——换完之后虽然通了,但在命令行的沙箱环境里还是不稳。最后干脆换了条路:不用 git 命令推送,改成直接调 GitHub 的 API,把文件一个个建成提交传上去。

备用通路大概长什么样
bash
# 编辑器里点"发布"时,先试常规推送;失败就自动切到这条
# 不依赖 git 命令,直接调 GitHub 的 API 建提交
python editor/api_push.py .

这条路反而更可靠,后来就把它固化成了博客编辑器的发布方式。现在编辑器点"发布",先走常规推送,失败了自动切到 API,两条路都断才报错。

塞翁失马。如果不是被那个死代理坑了一晚上,也不会想到去做这条备用通路。

排查要一路排到最底层

"网络慢"是一个可以解释一切的答案,所以它最危险。把链路拆开,一段一段测,才会发现真正断掉的是中间那一小截。

第三个坑:按钮点了没反应 ​

编辑器做出来之后,点"保存",屏幕上的状态提示一点变化都没有。

这次我的判断是:服务挂了。

于是查进程,活着。查端口,通着。查日志,没报错。反复重启,还是没反应。

折腾到后面顺手去看了一眼 git 记录,发现问题了——保存早就成功了,提交记录里明明白白躺着那一次修改。

真正坏的不是保存,是提示。我在页面脚本里用了 status 和 top 当变量名,这俩正好撞上浏览器内置的属性(一个是状态栏字符串,一个是窗口对象)。于是所有"已保存""发布中"的提示文字,都写到了一个没人看得见的字符串上。功能一直在正常工作,只是不吭声。

js
// editor/page.js
// 坏:status / top 是浏览器自带的,赋值不报错,但界面上看不到
status = '已保存'
top    = '发布中'

// 好:换成普通变量名,再拿它去更新页面上的元素
const tipEl = document.getElementById('tip')  
tipEl.textContent = '已保存'

改掉变量名,加上出错弹窗,好了。

功能故障和反馈故障要分开看

先把"事情有没有做成"和"有没有提示我"拆成两件事,各自验证。我当时要是再多怀疑一会儿自己,可能就去改一堆本来没问题的代码了。

真正要写的部分反而最顺 ​

编辑器本身没费什么劲——左右分栏写 Markdown、右边实时预览、一键发布,都没有引第三方库,纯标准库写的。

这么做的理由很直接:少一个依赖,少一处会崩的地方。 一个本地小工具,没必要为了省几行代码去装一堆包。

后来陆续加的左侧目录、搜索、暗色模式、归档页,也都很顺。真有问题的是往回看:这些功能本身不难,难的是搞明白前面那三个坑到底出在哪。

事后回头看 ​

我一开始的判断实际原因教训
数据没加载出来用了不存在的接口,静默失效不报错不等于成功
网络太慢环境里的代理是死的排查要一路排到最底层
服务挂了提示写错了地方,功能正常功能故障和反馈故障要分开看

三次我都先怀疑了错误的方向。相同点是:第一反应都是怪外部(缓存、网络、服务),最后发现都是自己没看清。

下一步 ​

先把文章稳定写下去。等攒够十篇左右,再考虑加评论区——现在加也没人评论,不急。

用 VitePress 搭的,托管在 GitHub Pages