Hexo博客Workflow,2026版
2018年写过一篇Hexo博客Workflow,记录了怎么把这个博客在本地架起来,再把文章发布出去。
八年过去,博客还是Hexo,主题还是自己改过的NexT。写博客之前要回忆的命令,却还是有点多:源码在一个repo,主题在另一个repo,要同步submodule,要装依赖,最后还要记得部署和提交源码。这些事单独看都不复杂,但隔很久才写一篇的时候,每一步都得重新想一遍。
所以这次把workflow整理了一下。目标很简单:我只管写和编辑Markdown,剩下的事情交给GitHub Actions。
写作、发布
所有需要编辑的东西现在都在src-blog-yiyu-me这个私有仓库里,包括文章、主题、配置和自动发布流程。
最简单的写法,甚至不需要在本地安装Hexo:直接在GitHub网页上打开这个仓库,在source/_posts/下面新建一个Markdown文件。例如my-new-post.md:
1 | --- |
提交到master,就会自动发布。修改旧文章也是一样:编辑对应的Markdown文件,再提交一次。
如果习惯在本地写,只需要clone这一个repo:
1 | git clone https://github.com/erain/src-blog-yiyu-me.git |
这是私有仓库,clone时需要使用有访问权限的GitHub账号。写好之后:
1 | git add source/_posts/my-new-post.md |
这里用git add,是因为新建的文件也要加进版本控制。剩下的安装依赖、生成网站、发布,都不需要在本地做。
文章链接依然按照日期和文件名生成。比如上面的例子,对应的是/2026/10/24/my-new-post/。修改旧文章时保留文件名和date,原来的链接就不会变。暂时不想发布的文章放在source/_drafts/;当前配置不会生成这些草稿。文章日期本身不是定时发布开关。
如果想先预览
本地预览是可选的。需要的时候,安装Node.js 24,然后在仓库目录运行:
1 | # 使用nvm管理Node.js的话,先读取仓库里的版本配置 |
打开http://localhost:4000,就能看到本地博客。没有使用nvm的话,直接安装对应版本的Node.js即可。
也可以让Hexo帮忙创建文章:
1 | npm run new -- "my-new-post" |
发布前想检查完整构建,可以运行npm run build。它会执行hexo clean和hexo generate,把网站生成到public/。这个目录不需要提交,GitHub Actions会自己生成一份。
背后是怎么工作的
编辑的入口只有一个仓库,但背后仍然保留两个仓库的分工:
| 仓库 | 保存什么 | 谁来更新 |
|---|---|---|
src-blog-yiyu-me,私有 |
Markdown、主题配置、Hexo配置、Actions配置 | 我 |
erain.github.io,公开 |
生成好的HTML、CSS、JavaScript等静态文件 | GitHub Actions |
主题已升级到NexT 8,通过npm安装,具体版本由package.json和package-lock.json锁定。自己的主题设置放在源码仓库的_config.next.yml里面,在Pisces双栏布局上做了适合中文长文的排版,首页用摘要展示文章。站点的样式在source/_data/styles.styl,首页模板在layout/index.njk。要改配置,就和改文章一样,在这个仓库修改、提交。原来单独的主题仓库和submodule都不再是日常流程的一部分。
网站继续由原来的GitHub Pages托管,域名还是blog.yiyu.me。这次主要是把手工操作自动化,没有换博客引擎,也没有换托管方式。
整个流程可以画成这样:
1 | 编辑Markdown、提交到源码仓库的master |
流程定义在源码仓库的.github/workflows/blog.yml里,分成build和deploy两个job。
build先取出源码,根据.nvmrc选择Node.js版本,再用npm ci按照package-lock.json安装依赖。这样不用依赖我电脑上碰巧装了什么。接下来执行完整构建,检查首页存在、CNAME里的域名正确,再把public/上传成一个名为blog-public的artifact,也就是这次构建的产物。
deploy必须等build成功后才能运行。它下载刚才生成的那份产物,把文件同步到发布仓库,提交并推送。同步时会删除已经不再生成的旧文件,保留发布仓库的Git记录;如果网站内容没有变化,就不产生新的提交。
最后,发布仓库的更新会触发GitHub Pages自己的构建和部署。源码仓库的Action成功,表示网站文件已经推送过去;还要等Pages部署成功,线上才算更新完成。
source/CNAME会随构建一起进入网站,继续使用原来的域名。发布时还会加上.nojekyll,让Pages直接提供Hexo已经生成好的静态文件。
两个仓库之间的钥匙
源码仓库的Action需要写入另一个仓库,因此单独配了一把SSH deploy key。公钥放在erain.github.io的Deploy keys里并允许写入,私钥放在源码仓库的Actions secret中,名字是BLOG_DEPLOY_KEY。
这把钥匙只对应发布仓库,不需要把我日常使用的个人SSH私钥交给Action。它是一次性配置,平时写文章不用碰。GitHub官方的deploy key文档解释了这种仓库级授权方式。
私有的是源码仓库,生成出来的网站仍然是公开的。写进正式文章的内容会发布到网上,这一点和以前一样。
怎么知道发布成功了
提交之后,先去源码仓库的Actions页面,看Build and publish blog这次运行是否成功。正常情况下,build和deploy都应该是绿色。
然后去erain.github.io的Actions页面,确认对应的pages-build-deployment也成功,最后打开文章的正式链接,检查标题、日期、正文、代码块,以及首页和归档里的入口。
如果build失败,先看构建日志,后面的发布不会执行,线上仍然保留之前的版本。如果deploy失败,检查发布日志和deploy key配置。如果两个job都成功、网页却没有更新,就继续看发布仓库的Pages任务,而不是只盯着源码仓库的绿色勾。
修正问题后再次提交,就会重新跑整个流程。也可以在源码仓库Actions页面选中这个workflow,用Run workflow手动重新发布master。Pull Request也会检查构建,但不会部署;合并到master后才正式发布。
八年前记下了怎么手动部署,八年后终于把部署这件事交给了机器。希望下次打开这个repo,是因为有东西想写。