hugo-logo-wide

在 2020 年的春节前夕,我终于完成了博客从 Hexo 到 Hugo 的迁移。期间踩过不少坑,也有不少小朋友来问我如何开始进行个人博客写作,因此觉着是时候写点东西记录记录。

Why Hugo

正式开始写个人博客,是两年前的春节。最开始使用了当时最流行的 Hexo 框架,选择了 Next 主题。最开始一切都很好,虽然 Hexo 框架是简单了点,但耐不住有很多热心的开发者开发了很多插件,所以基本上都能满足自己的需求。而随着博客数量越来越多,我发现 Hexo 的问题越来越让我难以忍受,那就是:速度太慢

举个例子,当我有 200 多篇博客的时候,用 Hexo 渲染静态网页需要将近 20 秒,这样的速度简直是不可接受的。更不要说我还有大量的静态图片、资料等等。同时,由于自己偷懒,博客中使用的图片都来自于图床,这些外链不受我控制,很多时候有打不开、加载慢的问题,让我这个强迫症觉得很不爽。

因此2019年底,我萌发了重构个人博客的想法,一眼就看中了用 Go 语言写的 Hugo,其Slogan The world’s fastest framework for building websites也是非常吸引我。更难能可贵的是,Hugo 虽然还处于快速迭代开发的阶段,但并不是一个半成品,很多在 Hexo 上需要插件实现的功能,Hugo 上都内置了。

Hugo vs Hexo

为了方便 Hexo 用户快速上手 Hugo,我总结了 Hugo 与 Hexo 的异同点(大部分来源于官网及这篇博文)。

结构组织

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
~/blog $ tree -L 1
.                     # 说明             Hexo
├── archetypes/     # 文章模板          scaffolds/
├── assets/         # Hugo 管道
├── config.toml     # 配置文件          _config.yml
├── content/        # 文章目录          source/_posts/
├── data/           # Hugo 数据文件     source/_data/
├── layouts/        # 布局模板
├── public/         # 生成的静态文件     public/
├── resources/      # Hugo 缓存
├── static/         # 网站的静态文件     source/
└── themes/         # 主题目录          themes/

在 Hugo 中,与 Hexo 的一个很大不同:是主题目录与站点目录有一样的结构,以 MemE 主题举个例子:

1
2
3
4
5
6
7
~/blog/themes/meme $ tree -L 1
.
├── assets/
├── data/
├── i18n/
├── layouts/
└── static/

其中,assetsdatalayoutsstatic 的作用都是与站点目录下的相应文件夹相同的,且站点目录下的文件可以覆盖主题目录下的相应文件——这意味着你可以在不修改主题文件的前提下方便地定制主题。

在 Hugo 中,如果你想要定制主题,你只需在站点目录下新建相应的文件即可。这是非常利于主题的维护的,你只需使用 Git 的 submodule 的方式安装 Hugo 的主题,然后更新时只需直接在站点根目录下敲一条命令回车即可,非常方便。

此外,上面的 i18n 文件夹相当于 Hexo 的主题中的 languages 文件夹,如果你不喜欢主题的一些文字翻译,可以在站点目录下新建相应文件自定义。这里特别需要提醒的是,Hugo 中的 datai18n 文件夹下的所有文件都是可以按「键」覆盖的,即你无需复制文件全文,只需添加你想自定义的那项即可。

配置文件

Hugo 中是不区分站点和主题的配置文件的,Hugo 中只有一个位于站点根目录下的 config.toml 配置文件。你可能注意到 .toml 后缀,没错,Hugo 默认使用的配置文件是 TOML 格式的,它的语法是非常简单易懂的,它在语法上也没有缩进的要求。当然,在 Hugo 中你也可使用 Hexo 默认的 YAML 格式,但我还是建议你使用 TOML,毕竟入乡随俗嘛。此外,如果你想将文章中的 Front Matter 也从 YAML 转换成 TOML 的话,推荐一个 Python 脚本。但特别注意:尝试前务必先备份!

分类方式

我们知道,在 Hexo 中有两种分类方式——分类和标签,它们都是在文章的 Front Matter 中设置的,其中:categories 是具有顺序性和层次性的,即你可以通过它来实现树状结构的分类;tags 则没有这种特点,它的作用只是将不同的文章联系起来。由于 Hexo 中的 categories 具有这样的特点,因此在 Hexo 中 categories 可以作为一种文章的组织方式——在 Hexo 中你可以将 categories 用在文章的 URL 结构中。

但是在 Hugo 中这是无法实现的,在 Hugo 中你是无法将文章的 Front Matter 中的 categories 用于文章的 URL 的。为什么呢?因为 Hugo 中的 categoriestags 在功能上其实是完全相同的,它们的作用都是将不同的文章联系起来。其实,Front Matter 中的 categoriestags 在 Hugo 中都属于 Taxonomies。

那么,在 Hugo 中你要怎么组织文章呢?分区(Sections)。所谓分区,即站点的 content 目录下的文件夹和子文件夹,一个文件夹即一个分区。很明显,这是基于文件系统的结构的,自然也就支持树状╱网状╱嵌套结构,也就能够用来实现文章的树状分类。

我认为这是一个非常好的设计,在使用Hexo时,博客数量一多,在本地的文件系统中就容易混乱,我还使用了一个插件,来自动将文件夹名字用于Front Matter中的 categories ,而在Hugo中直接就使用了这种分类方式。需要注意的是,如果有多级文件夹,需要在文件夹下新建_index.md使得其为新的categories

其它方面

首先是文章的 Front Matter 中的 date 日期格式的问题。在 Hugo 中,Hexo 默认的日期格式是不能工作的,比如:你必须要修改 1969-07-20 20:17:431969-07-20T20:17:43+00:00即添加了时区的信息。对于这点,你可以用上文提到的那个 Python 脚本批量处理一下。

然后是文章的修改时间的问题。在 Hexo 中,会自动将文件的修改时间作为文章的修改时间,但在 Hugo 中不会。不过你可以自行配置,在配置文件 config.toml 中加入 :fileModTime

1
2
[frontmatter]
    lastmod = ["lastmod", ":git", ":fileModTime", ":default"]

如此,就算你没有在文章的 Front Matter 中手动指定修改时间 lastmod,它依然会随着你的文章的改动或修改而「自动更新」。


在 Hexo 中,你可能会在 Markdown 中使用 Hexo 标签插件来实现一些 Markdown 语法无法实现的特殊排版需求。这些特殊的语法是无法在 Hugo 中生效的,尽管在 Hugo 中有与之对应的短代码,但它们之间的语法是不同的,故我建议最好放弃这种非 Markdown 原生语法的写法。当然,如果你非要手动将之从 Hexo 迁移到 Hugo 中也不是没有可能,比如:你可以用 hugo-notice 实现 NexT 主题的 Note 标签

此外,对于文章摘要的截取,即「阅读更多」上方的内容。在 Hexo 中你可以在文章中加入<!-- more --> 来控来控制,但这在 Hugo 中是不会生效的,在 Hugo 中你必须将空格删除。

还有一个是 index.md 的问题,在 Hugo 中你必须在它的前面添加一个下划线,即 _index.md。比如:你想自定义标签页面的标题为中文,那么你先在新建一个 content/tags/_index.md 文件,然后在文件中加入:

1
2
3
+++
title = "标签"
+++

对于图片,我个人建议还是使用本地图片,而不是图床(血的教训)。在 Hugo 中,使用本地图片的方法很简单,直接在 static 文件夹中新建一个 images 子文件夹,然后在Markdown语法中使用:

1
![hugo-logo-wide](/images/misc/hugo-logo.svg "Hugo")

其中,最后的 Hugo 是图片的描述。

Hugo theme

Hugo 是一个很活跃的社区,有非常多的主题可供选择。我目前的主题选择的是 MemE,开发者非常活跃且乐于接受 PR,同时审美在线,速度非常快,我非常满意。

开发者 reuixiy 有详细的主题开发介绍,我这里就不赘述了。

由于 MemE主题使用了大量 SVG 图片来加快加载速度(包括品牌栏、图标等等),我使用了 Inkscape 来制作了自己的品牌栏(还不错吧?),可供大家参考。


下一篇博客我会介绍,如何使用 Hugo 进行持续集成写作,同时同步到个人服务器中。