博客系统迁移:Hexo 到 Hugo
文章目录
上一篇文章介绍了 Emacs 的理念以及其强大的扩展功能,基本上能在 Emacs 里面做到事,我都在 Emacs 里面做。之前的博客一直都是用的 markdown 来书写,虽然 Emacs 也有 markdown 插件,但是总感觉体验不如 org-mode。这周末就趁着手热,把博客系统进行了升级,完美支持 org-mode,这篇文章就是用 org-mode 完成的,下面就来讲一下迁移过程。
Hexo vs Hugo
最近两年一直在用 hexo 来写博客,记得静态托管类网站刚兴起时,hexo 是比较流行的,整个生态也比较完整。这次迁移博客系统时,决定不再用 hexo,原因主要有下面几个:
-
安装烦。作为一个 Node.js 写的系统,安装时需要下载大量的
node_modules
。这一点不是很核心,毕竟安装只是一次性工作 -
升级难。记得当初在 hexo 2 升级到 3 时,遇到过不少坑,对 Node 的版本也有要求,如果部分依赖用了 C 代码(比如 node-sass),安装起来也比较费劲;现在 hexo 大版本已经到了 5.2.0,不想再去折腾
-
原生不支持 org-mode,使用了下 hexo-renderer-org 插件,也没成功,而且其作者现在也没精力来维护了
基于以上几点,hexo 于我而言,不再是最佳的选择,当然并不是说它不优秀,Hugo 也很有可能有类似问题。我之所以选择 Hugo 主要有两个原因:
-
基于 Golang 的 Hugo 实现,安装方便,只需一个二进制文件;而且最近两年我个人也一直在用 Golang 开发,比较熟悉
Hugo 使用方式比较简单,这里不再赘述,新手可参考官方 Quick Start。
迁移过程
旧博客备份
文章链接
对于个人博客的迁移而言,保证文章链接不变是最重要的。在 hexo 中,文件名与链接的对应关系如下:
|
|
对应的 markdown 文件是
|
|
这样的好处是文件按照时间排列,管理方便。
Hugo 则不同,它默认会用文件中 frontmatter 的 date,而非文件名中的。我已经习惯了 hexo 的组织方式,不想去改变,经过一番探索,最终在 hugo 添加下面的配置完美解决:
|
|
这样 Hugo 就会首先从文件名中解析日期,同时也会解析 slug;失败时再从 frontmatter 中解析,更多用法可参考官方文档 Configure Dates。
同时,为了避免 hugo new post/year-month-day-slug.org
时标题中带日期,修改默认模板如下:
|
|
RSS 链接
默认 Hugo 生成的 RSS 链接为 /index.xml
,而我之前用的是 /atom.xml,可以通过如下配置修改:
|
|
Tags 链接
Hugo 中默认会把链接中的字母变成小写,比如标签 Go
,在之前对应地址 /tags/Go
,换成 Hugo 后则是 /tags/go
,可以通过下面的配置关闭这个转化。
|
|
如果想保留这个功能,可以进行下面的操作:
|
|
这时 git status
会显示
|
|
然后提交就可以了。
Frontmatter
Frontmatter 定义了每篇文章的属性,比如标题、分类等。这也是在 hexo 迁移到 hugo 时问题最多的地方,根本原因在于 hexo 对 frontmatter 格式较宽松,而 hugo 则比较严格。
下面一个 hugo 中标准的 frontmatter(除 yaml 外,还可以是 toml/json):
|
|
主要有两点需要注意:
-
categories/tags 这两个属性必须是数组
-
frontmatter 前后需要用
---
包起来,与正文区分
而在 hexo 中,
-
categories/tags 可以是数组,也可以是字符串,表示一个元素的数组
-
只需要 frontmatter 末尾强制用
---
与正文区分,前面的不做要求
由于我文章较多(72篇需要迁移),且格式也都不一样(可能是 hexo 2/3 的区别),因此写了两个脚本来辅助,最终生成符合 hugo 要求的 frontmatter。如果 frontmatter 格式不对,可能会遇到下面的错误:
|
|
说明 categories 或 tags 有不是数组的,需要改成数组
|
|
说明缺少了 frontmatter 结尾的分隔符,如果缺少开头的分隔符,编译文章没有错误,但是最终生成的文章页面会没有标题。
Categories
在 hexo 中分类(category) 和标签(tags) 用法是不一样的,分类可以有层次,比如:
|
|
标签则没有;在 hugo 中分类与标签用法一样,都只有一层。由于我之前博客就没有用到多层分类的情况,所以也就不需要额外处理了。
其次,在 hexo 可以通过 category_map/tag_map 来定义 category/tags 的固定链接地址(即 slug),虽然我之前也了这个特性,但是这次并没有去适配,采用 hugo 默认的即可。有修改需求的读者可参考:
Render hook
markdown 中引用图片的标准做法是
|
|
但是我一般只写 alt,title 基本没写过,之前使用的主题 maupassant 默认会把图片的 alt 显式在图片下面,而 hugo 只认 title,搜索发现可以通过 hugo 提供的 markdown render hook 来实现。方式如下:
-
创建
layouts/_default/_markup/render-image.html
文件 -
添加内容
1 2 3 4 5 6 7 8
{{ if .Text }} <figure> <img src="{{ .Destination | safeURL }}" alt="{{ .Text }}"> <figcaption>{{ .Text }}</figcaption> </figure> {{ else }} <img src="{{ .Destination | safeURL }}" alt="{{ .Text }}"> {{ end }}
对于 org-mode 而言,直接采用下面的方式即可:
|
|
修改记录
本次迁移的所有修改可以在 Github 中查看,供有相同迁移需求的读者参考。
Easy-hugo
经过上面的步骤,已经可以很好的把 hexo 迁移到 hugo,下一个要解决的问题就是如何用 Emacs 管理 Hugo。Hugo 官网上列举了一些与常用编辑整合的插件,这里介绍 easy hugo 的使用方式。
配置
由于目前我又两个博客(中文和英文),因此需要做些配置让 easy hugo 识别这两个。
|
|
创建新文章
虽然可以用 hugo new post/xxx.org
的方式来创建新文件,但是由于文件名中需要有固定格式的日期,每次手动输入很繁琐,因此基于 easy hugo 的多博客管理,自己实现了 hugo-newpost
函数,实现如下:
|
|
这样就可以通过调用 my/hugo-newpost
自动生成带日期的文件名,并且根据输入生成指定的 slug/title/tag/category。

由于目前我全局开启了 evil mode,需要把 easy-hugo-mode 添加到 evil-emacs-state-modes 里面去才能使用 easy-hugo 的快捷键,顺道解决了 easy hugo 的一个 bug。完整配置可参考这次的 Git 提交。
easy-hugo 还提供了预览、发布(默认调用 deploy.sh)等命令,比较简单,这里不再赘述。
总结
屠龙刀已经磨好了,下面就需要多去动“刀”写出更多文章了。