我为什么要从 Hexo 更换到 Hugo

前言

最近比较烦的是我的博客本以为很完美了,不用再折腾了,没想到 Hexo 有一个很大的弊端。我忍痛割爱的计划将 Hexo 引擎更换为基于 Go 语言的 Hugo 模板引擎。Hexo 优点很多,缺点就是生成静态文件 (hexo g) 速度真的是太慢了。Hexo 是基于 Nodejs 的,有很多插件,而 Hugo 没有插件,使用自带的 Go html 模板实现, 这个速度真的是牛,基本上在 Hexo 上面十几分钟,使用 Hugo 只需要几秒钟。

在更换过程中我想保留我原来博客的主题风格,所以很多东西都是逐渐仿照实现过去的,但是最让人头疼的并不是去实现这些功能,而是迁移过程中为了防止路径不同(大小写)和 keywords description 的不同导致的 SEO 问题。 其实目前我已经完全实现模板复制,但是我还是计划花一两个月慢慢迁移过去,这样对本站的影响可以尽量做到最小。

搭建 Hugo

下载地址:https://github.com/gohugoio/hugo/releases

官网下载二进制安装包,然后配置环境变量:

C:\Program Files (x86)\hugo_0.57.2_Windows-64bit

如果你是 Mac Os 可以使用 Homebrew 可以安装 Hugo:

brew install hugo

然后就可以愉快的开始了, 创建博客 blog 站点:

hugo new site blog

安装主题,直接将主题代码 clone 到 themes 目录下即可:

git init
git submodule add https://github.com/olOwOlo/hugo-theme-even.git theme/even

新建博文:

hugo new post/test.md

查看生成效果,实时预览:

hugo server

当然,这里你可以指定端口(默认端口:1313) hugo server --port 8080,也有一些其他参数我们后续会专门写一篇文章对 hugo 的命令进行详解。

更换的坑

时间格式

Hexo 中时间格式与 Hugo 格式不太相同,Hugo 对时间格式的要求比较严格,Hexo 中 YYYY-MM-DD HH:MM 格式的时间在 Hugo 中无法被正确识别。Hugo 中使用的时间格式 如下:

date: 2017-11-30T17:46:58+08:00

最后的 +08:00 代表中国的时区是 GMT+8。

文章路径

Hexo 中,文章的链接都是 YYYY/MM/DD/post_name/ 的格式,在 Hugo 中,可以通过设 置 permalinks 参数来实现平滑过渡,在 config.toml 中加入以下设置:

[permalinks]
    post = "/:year/:month/:day/:filename/"

路径大小写

在 Hexo 中文章路径中的大写字母保留,分类和标签的大小写也是保留的,在 Hugo 中默认会转换为小写,我们需要在 config.toml 中配置如下两行:

# Hugo 默认会把 url 中的大写字符转为小写
disablePathToLower = true
# Hugo 默认会把Taxonomy(categories,tags,series)名称转为小写
preserveTaxonomyNames = true

如果出现路径访问不到,你就要查看一下生成路径的地方是否强制进行了转换,删除强制转换代码即可。

设置草稿

在文章头部设置 draft 为 false 才可见,否则就是草稿,不会发布。

draft: false

工程结构

比较重要的文件目录有 content, themesstatic 另外还有一个 archetypes:

在 content 目录下我们可以放置文章,类似于 Hexo 的 sourc 目录, static 目录存放一些静态资源,类似于 Hexo 中配置的 skip_render,可以将图片,静态demo网页等放入,archetypes 中可以创建一个 default.md 文件来定义创建文章的模板:

---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
description: ""
categories: [""]
tags: [""]
draft: true
---

Go html/template

文档地址:https://golang.org/pkg/html/template/

Hugo 的模板是基于 Go html/template 的,所以一些基础变量和函数可以在 Hugo 中使用,例如:

{{ if or (not (isset .Params "prevnext"))  .Params.prevnext }}
    {{ partial "prev_next_post" . }}
{{ end }}

上面的 or, not, isset 关键字其实对应的是一个 Go 函数,可以使用模板实现结构化数据渲染。当然在 Hugo 中也定义了不少变量和函数:

变量请参考文档:https://www.gohugo.org/doc/templates/variables/ 函数请参考文档:https://www.gohugo.org/doc/templates/functions/

实现归档页

在 Hugo 中默认只生成 tags 和 categories 两个页面,没有 archives (归档)页面,所以我们需要自己实现:

首先,在 themes/主题/layouts 目录创建一个目录 archives 然后在里面新建一个文件 single.html, 注意我们接下来要覆盖 themes/主题/layouts/_default/baseof.html 中的 main 模块:

{{ define "main" }}
<link rel="stylesheet" href="{{ "css/archives.css" | absURL }}">
<article class="article article-type-post" itemscope="" itemprop="blogPost">
    <div class="article-inner">
        <div class="post-archive">
            {{ range (where (where .Site.Pages "Type" "post") "Kind" "page").GroupByDate "2006" }}
            <h2> {{ .Key }} </h2>
            <ul class="listing">
                {{ range .Pages }}
                <li>
                    <date class="meta-date">{{ .Date.Format "2006/01/02" }}</date>
                    <a class="archive-title" href="{{ .Permalink }}" title="{{ .Title }}">{{ .Title }}</a>
                </li>
                {{ end }}
            </ul>
            {{ end }}

        </div>
    </div>
</article>
{{ end }}

接着在 content 目录创建文件 archives.md 将 type 设置为 archives 就可以了:

---
title: "归档"
type: "archives"
prevnext: false
---

总结

在 Hugo 中定一个页面模板 baseof.html 我们可以去修改这个模板,然后再去填充或者覆盖对应的区域,总体来说还是比较有规律的,虽然我是个 Go 盲(之前没用过 Go 语言),而且是个半吊子前端(我是做 Android 的),改起来还算是顺畅,没有遇到什么特别大的问题。比较遗憾的也是最让我纠结的是 Hugo 中生成文章的结构和 description 有些不同,所以我最后忍痛修改了部分页面的 description 就上线了,希望对本站的 SEO 没有太大的影响吧,乞求上帝。

最后放出一张我使用 Hugo 修改主题后的网站缩略图和 Hexo 修改主题的缩略图比较。

Hexo 模板引擎实现的本站示意图 Hugo 模板引擎实现的本站示意图