使用hugo+asciidoctor在GitHub搭建博客

为什么要使用 hugo + asciidoctor 这样的组合

hugo 对自己的介绍是 The world’s fastest framework for building websites。 GitHub 有非常多的项目主页和个人博客都是用 hugo 生成的。hugo 相对于同类竞品比如 jekyll 最大的优势是

hugo 最常见的搭配是 Markdown。Markdown 差不多也是最通用的标记语言(不包括 HTML)。Markdown 使用范围比较广的有 2 个规范, CommonMark 和 GFM(GitHub Flavored Markdown)。使用最广泛的标记有如下几种

一级标题
=======

## 二级标题

段落以空白行分隔。

行末两个空格  产生换行。

文本属性:_斜体_、
**粗体**、`等款字体Monospace`。

水平线:

---

列表:

  * 张三
  * 李四
  * 王二

编号列表:

  1. 不论
  2. 三七
  3. 二十一

[链接](http://example.com)

![图片](Icon-pictures.png "icon")

> Markdown使用「>」來引用。


```
代码片段,GFM
```

~~删除线 GFM~~

[] 任务列表1 GFM
[] 任务列表2 GFM
[x] 已完成的任务列表 GFM

这几种标记看起来非常简单,但是在实际使用的时候,往往不遂人意。

比如希望在嵌套编号列表中插入多个段落,实现如下的排版:

  1. 编号 1

    代码片段

    编号 1 段落 2

    1. 嵌套列表 1.1

      嵌套列表代码片段

      编号 1.1 段落 2

    2. 嵌套列表 1.2

  2. 编号 2

用 Markdown 往往需要调试非常多次,而且不同的编辑器最终排版还会有不一样的表现。

日常的写作中,往往需要插入丰富的内容,比如插入表格,视频,公式,下标、上标等。Markdown 除了内嵌 HTML 代码并没有提供其他扩展的能力。 这就导致了每个人用 Markdown 写文档的时候,或多或少需要使用 HTML 标记。

插入视频
<video id="video" controls="" preload="none" poster="http://media.w3.org/2010/05/sintel/poster.png">
  <source id="mp4" src="http://media.w3.org/2010/05/sintel/trailer.mp4" type="video/mp4">
  <source id="webm" src="http://media.w3.org/2010/05/sintel/trailer.webm" type="video/webm">
  <source id="ogv" src="http://media.w3.org/2010/05/sintel/trailer.ogv" type="video/ogg">
  <p>Your user agent does not support the HTML5 Video element.</p>
</video>

Markdown 本来定位是标记语言,并不与浏览器绑定,但是一旦使用 HTML,就意味着只能在浏览器里面渲染。而且由于不同的 Markdown 编辑器、渲染程序 实现功能不一样,同一份 Markdown 文档,在不同的平台使用,都需要人工做一些修改。[1] [2]

Asciidoctor 在 Markdown 的基础上,重新设计了一套根据完善的标记语言,很好地解决了 Markdown 遇到的问题。这篇文章就是用 Asciidoctor 写的。 具体的格式可以参考 Asciidoctor 官网

只需安装好 asciidoctor 命令,hugo 就可以支持用 Asciidoctor 格式写文档。

如何自动部署 Github Pages

本地写文章的时候直接一行命令启动 hugo,就可以在浏览器预览文章。

hugo server

我们想实现:写完文章后只需要 push 到 GitHub,后面生成文章的过程全部自动化。

现在 GitHub 主流的自动化方式是使用 Github Actions。Repo 收到 push 事件后,触发 GitHub Action。由 GitHub Action 调用 hugo 生成 整个静态网站,然后将生成的所有静态文件提交到 GitHub Pages。

目前 GitHub Pages 有多种机制:

pages-source-choose

博客的 repo 名称为 gfreezy.github.io,属于 User Pages,只支持通过 master 的根目录访问。所以 hugo 生成的文件需要放在 repo 的 根目录。这样一来生成的文件和 hugo 原始的代码文件都混合在 repo 的目录,非常不利于长期维护。既然生成的文件位置没法修改,那我们就把 hugo 代码放在子目录 hugo 里面,根目录只放生成的文件。

这引入了一个新的问题:GitHub Action Market 里面的 hugo action 都只支持在 repo 根目录运行。找了一圈没有合适的,我们只能自己来写 action。

workflow.yml
name: github pages

on:
  push:
    branches:
      - master

jobs:
  deploy:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@v2
        with:
          submodules: true  # Fetch Hugo themes
          fetch-depth: 0    # Fetch all history for .GitInfo and .Lastmod

      - uses: actions/setup-ruby@v1  (1)

      - name: Publish Site
        run: make  (2)

      - name: Deploy
        uses: stefanzweifel/git-auto-commit-action@v4.1.2  (3)
        with:
          commit_message: hugo publish
1 asciidoctor 需要使用 gem 安装。需要准备好 ruby 环境
2 生成网站
3 将新生成的代码 commit,并 push 到 master
Makefile
HUGO_VERSION:="0.69.0"
ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
BIN:="$(ROOT_DIR)/.bin"
ifeq ($(shell uname), Darwin)     (1)
	OS:="macOS"
else
	OS:="Linux"
endif

.PHONY: build    (2)

build: clean install   (3)
	cd $(ROOT_DIR)/hugo && $(BIN)/hugo
	mv $(ROOT_DIR)/hugo/public/* $(ROOT_DIR)/

install: .bin/hugo

.bin/hugo:   (4)
	# install asciidoctor
	[ $(OS) == "macOS" ] && brew install asciidoctor || gem install asciidoctor

	# install hugo
	mkdir -p ".bin"
	[ -f hugo_extended_$(HUGO_VERSION)_$(OS)-64bit.tar.gz ] || wget https://github.com/gohugoio/hugo/releases/download/v$(HUGO_VERSION)/hugo_extended_$(HUGO_VERSION)_$(OS)-64bit.tar.gz
	tar -C .bin -xzvf hugo_extended_$(HUGO_VERSION)_$(OS)-64bit.tar.gz
	rm -rf hugo_extended_$(HUGO_VERSION)_$(OS)-64bit.tar.gz

clean:   (4)
	ls $(ROOT_DIR) | grep -v -E '^(CNAME|Makefile|hugo|README.md)$$' | xargs rm -rf || true
	rm -rf $(ROOT_DIR)/hugo/public/
1 判断 macos 和 linux
2 默认执行 build
3 每次 build 前,先执行 clean。避免无效的文件影响显示效果
4 将所有生成的文件全部删除

完成

之后写博客,只需要新建一个 asciidoctor 文档,写完后提交并 push master,后续全部都自动化。 GitHub 是支持预览 asciidoctor 文档的,所以我们甚至可以直接在 GitHub 上在线创建和编辑。