月底升级了 Copilot Pro+,月初额度重置,这几天可以放开用,想到什么就 vibe 一把。
我的博客跑在 Hexo 上很多年了。其实没什么大问题,就是每次看到那几百 MB 的 node_modules,心里总有点膈应——生成几百个静态 HTML,真的需要这么多依赖吗?但迁移到别的博客系统又懒得折腾,所以一直拖着。
这次干脆试试:能不能用 AI 一个下午撸一个 Rust 版的 Hexo?我的目标比较简单:生成跟原来一样的静态文件,兼容我现在用的主题就行。
我用的是 OpenCode + Opus 4.5。陆陆续续聊了一下午,产出了 hexo-rs。能用,但还有些边边角角的问题。
Vibe Coding 的工具和体会以后再写,这篇主要聊 hexo-rs 的实现和踩过的坑。
技术选型
EJS 模板引擎
Hexo 主题基本都用 EJS 模板——就是把 JavaScript 嵌到 HTML 里,跟 PHP 差不多。
用 QuickJS 跑 JS,通过 quick-js crate 调用。好处是不用依赖 Node.js,坏处是 Windows 上编不过(libquickjs-sys 挂了),所以暂时只支持 Linux 和 macOS。
其他
Markdown 用 pulldown-cmark,代码高亮用 syntect,本地服务器用 axum。都是常规选择,没什么特别的。
踩过的坑
HashMap 的坑
这个 bug 藏得很深。生成 tag 和 category 页面时,一开始用 HashMap 存文章分组:
let mut tags: HashMap<String, Vec<&Post>> = HashMap::new();
HashMap 迭代顺序不确定,每次生成的 HTML 可能不一样。页面看着没问题,但 diff 一下就发现乱了。改成 BTreeMap 就好了:
let mut tags: BTreeMap<String, Vec<&Post>> = BTreeMap::new();
Helper 函数
Hexo 有一堆 helper 函数:url_for、css、js、date 之类的。都得在 Rust 里实现一遍,然后塞进 QuickJS。
最烦的是 date。Hexo 用 Moment.js 的格式(YYYY-MM-DD),Rust 的 chrono 用 strftime(%Y-%m-%d)。得写个转换函数,挺无聊的活。
Partial 嵌套
EJS 的 partial 可以套娃,A 引用 B,B 又引用 C,变量还得一层层传下去。搞了个作用域栈,进 partial 压栈,出来弹栈。不难,但容易写错。
Vibe Coding 体感
代码 100% 是 AI 写的。我干的事:描述需求、review 代码、把报错贴给它让它改、偶尔拍板选方案。
像 EJS 模板引擎这种东西,自己从头写估计得半天,AI 几分钟就吐出来了。
但 AI 也挺蠢的:
- HashMap 那个 bug 它就没注意到,我提出界面上的变化它也没反应过来
- 一开始它写的 EJS parser 全是字符串 hardcode,丑得不行,我让它按 lexer -> AST 的套路重写了一遍
- 代码多了以后它会忘事,前面写过的逻辑后面又写一遍
但 AI 又确实非常强,我想到应该使用现在线上的 catcoding.me 来和新生成的内容一一对比,然后它就呼啦啦地一通操作把问题都找出来了,自己修改完。
使用
cargo binstall hexo-rs # 或 cargo install hexo-rs
hexo-rs generate # 生成静态文件
hexo-rs server # 本地预览
hexo-rs clean # 清理
hexo-rs new "标题"
局限
不支持 Hexo 插件,不支持 Stylus 编译(.styl 文件得先用 Node 编译好),Windows 也不行。
简单的博客应该够用。复杂主题可能会有兼容问题。
代码在这:github.com/chenyukang/hexo-rs
用 Hexo 的可以试试。有问题提 issue,我让 AI 来修 :)
这篇文章到底是人写的,还是 AI 写的?