# 用Hugo创建静态网站

## 前言

最近在学习[IPFS](https://ipfs.io/)，发现这东西用来托管静态网站简直完美——以内容为中心、分布式、防篡改、抗审查。即然如此，不如在IPFS上作个Blog来玩儿玩儿。

不过不管咋托管，总得先搭个Blog框架出来，自然就想到了Hugo。由此本站第一篇文章便是Hugo的简单教程。

## Hugo 是啥

[Hugo](https://gohugo.io/) 是一个静态网站生成工具。 它是用Golang编写的，运行效率极高。号称全世界最快。

是不是最快我不确定， 但它是单一Binary、无依赖、无需复杂安装且全平台可用。 这些特点就足够吸引我了。

与它相比，[Jekyll](https://jekyllrb.com/) 用Ruby编写，安装维护的方便程度和运行效率上都会略逊一筹。

来自NodeJS社区的 [Hexo](https://hexo.io/) 就更不用考虑了 —— 是的，我对NodeJS有偏见。只要可能，就会选择远离它^-^。至于具体原因，以后有机会可以专门写一个系列。

## 快速上手

既然选定了工具， 就立即开始。

#### 建立源码仓库

先在github上建个仓库，用来跟踪承载原始内容的Markdown文件。先把这个空的仓库克隆到本地（这里以我的私有仓库为例，你得换成你自己的）

```bash
git clone https://github.com/dche423/blog.git
```

#### 安装Hugo并初始化网站

根据[Hugo官方文档](https://gohugo.io/getting-started/quick-start/)，这个过程还是非常简单的。 与官方文档一样， 本文也以macOS为例， 其它平台差别不大。

先用 Homebrew 安装

```bash
brew install hugo
```

运行hugo命令以便验证是否安装成功

```bash
$ hugo version
Hugo Static Site Generator v0.69.0/extended darwin/amd64 BuildDate: unknown
```

创建名为blog的新站点

```bash
$ hugo new site blog
Error: /dche423/blog already exists and is not empty. See --force.

$ hugo new site blog --force
Congratulations! Your new Hugo site is created in /dche423/blog.
...
```

默认情况下， 如果站点目标文件夹存在且不为空，hugo 不会执行创建动作。 只有当我们指定了 `--force` 参数时，创建才能成功。

接下来需要为站点选择一个主题， 这里我使用了与官方教程一致的 [Ananke](https://themes.gohugo.io/gohugo-theme-ananke/)。 当然， 你可以按自己的喜好选其它主题。 [Hugo主题站](https://themes.gohugo.io/)上有非常多的选择。

```bash
cd blog
git submodule add https://github.com/budparr/gohugo-theme-ananke.git themes/ananke

echo 'theme = "ananke"' >> config.toml
```

这里把主题的git仓库作为submodule 加到了站点之中, 以便后续持续更新。主题下载了之后，要编辑配置文件`config.toml`，为站点启用此主题。

#### 创建文章

虽然也可以手工在相应目录下创建文件， 但用`hugo` 命令会方便一点，这个命令会自动生成文件， 并为文件填写基础的元数据：

```bash
hugo new posts/build-site-with-hugo.md
```

生成的Markdown文件内容如下，仅包括了几条[Front Matter](https://gohugo.io/content-management/front-matter/.html)格式的元数据：

```plaintext
---
title: "Build Site With Hugo"
date: 2020-05-27T16:02:20+08:00
draft: true
---
```

其中的 `title` 和 `date` 比较直观，不作解释。

`draft` 属性表明了此文章尚处于草稿状态。在部署环节不会真正生成页面。 如果撰写内容已经完成， 那么可以把这个属性改为 `false`， 这时便可以真正部署了。

#### 启动Hugo服务器

下面就可以启动Hugo服务器在本地查看网站的效果了：

```bash
$ hugo server -D


                   | EN  
-------------------+-----
  Pages            | 10  
  Paginator pages  |  0  
  Non-page files   |  0  
  Static files     |  3  
  Processed images |  0  
  Aliases          |  1  
  Sitemaps         |  1  
  Cleaned          |  0  

Built in 26 ms
Watching for changes in /dche423/blog/{archetypes,content,data,layouts,static,themes}
Watching for config changes in /dche423/blog/config.toml
Environment: "development"
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop
```

注意启动时增加了 `-D` 参数， 它的作用是确保处于草稿状态的文章也可以显示出来。

此时访问 [http://localhost:1313](http://localhost:1313) 就会看到网站的首页（虽然目前还没有什么实质性的内容）。

注： `1313` 是Hugo 服务器的默认端口， 如果此端口已被其它服务占用， Hugo 会自动切换到其它可用端口。

保持服务器运行的情况下， 修改文章后打开本地网站的浏览器会自动刷新以显示最新内容。

至此， 一个最基本的网站框架便建成了。

## 定制网站

虽然有了网站框架， 但有些基本信息还需要进一步修改和定制。

#### 调整基本信息

首先看 `config.toml` 文件

```toml
baseURL = "https://example.org/"
languageCode = "en-us"
title = "My New Hugo Site"
theme = "ananke"
```

其中最后一行是刚才设置主题时加入的。

`title` 和 `baseURL` 都需要根据实际情况作出修改。修改后的内容变成：

```toml
baseURL = "/"
languageCode = "en-us"
title = "爱扯淡"
theme = "ananke"
```

注意，这里我们并没有把 `baseURL` 改成某一个具体域名下的地址 (比如[https://www.chedan.io/](https://www.chedan.io/))，原因在于我们希望同一份HTML文件既可服务于传统域名地址，也能够很好地在分布式web的地址下工作。后续文章将详细解释此处的权衡。

#### 调整文章摘录

网站的首页是文章列表，列表中每一条包含文章标题和文章摘录。

默认情况下，Hugo 会选取文章的前70个单词作为摘录内容此处单词的定义是空格分隔的词语。

如果是东亚文字， 则需要把 `hasCJKLanguage` 配置项设为 `true`，这时就变成选取前70个字了。数字70可以通过 `summaryLength` 配置项进行调整。

另外也可以通过 `plainify` 和 `safeHTML` 函数来控制摘录中HTML的表现。这需要自己定制模板，这里不作展开说明，具体可以查看 [模板文档](https://gohugo.io/templates/) 和 [函数文档](https://gohugo.io/functions/)

除了自动截取， Hugo还支持两种手动设置摘录的方式：

1. 在文章中插入 &lt;!--more--&gt; 分隔符。 分隔符之前的文本会成为摘录内容。
    
2. 利用 Front Matter 元数据单独编写摘录。 这种方式的好处很明显， 摘录与内容不直接相关，由作者自己灵活总结。 并且支持任意HTML格式。 坏处就是增加了手工工作量。 要使用这种方式， 需要在文章Front Matter部分增加 `summary` 元数据。(本文便选择了这种方式)
    

如果以上多种摘录信息都被设置了， 则系统显示的优先级为

```plaintext
分隔符 > Front Matter > 自动摘录
```

更多摘录相关设置， 可以看[这里](https://gohugo.io/content-management/summaries/)

#### 关于语法高亮

Hugo内建支持代码块的语法高亮。无需定制，开箱即用。不仅如此，它还通过 [Highlight Shortcode](https://gohugo.io/content-management/syntax-highlighting/) 提供了更灵活的控制。比如行号显示，单行标注等等。

#### 显示章节目录(TOC)

要显示章节目录，只需要在Front Matter中增加 `toc`。

```yaml
toc: ture
```

需要注意的是，hugo 默认情况下只在TOC中显示二级和三级标题，相当于在`config.toml`中配置了如下项目。

```toml
[markup]
  [markup.tableOfContents]
    endLevel = 3
    startLevel = 2
```

如果想修改， 则可以调整相应的数字。不过根据官方的建议， TOC不宜级别太多，以防大量缩进而失去可读性。

此外， 似乎Hugo 0.6.x 的TOC缩进显示有问题。例如 [#6613](https://github.com/gohugoio/hugo/issues/6613)，[#6623](https://github.com/gohugoio/hugo/issues/6623)。好在一般情况下我们并不需要TOC的多级缩进。

#### 设置站点favicon、主图和文章的头图

站点favicon和主图可以在`config.toml`中设置：

```toml
[params]
  favicon = "favicon.ico"
  featured_image = "/sfo.jpg"
```

要为文章增加头图，只需要在文章 Front Matter 中增加一项

```yaml
featured_image: /hugo-logo-wide.svg
```

按照Hugo官方建议，图片资源应该放到 `./static` 目录下。

此头图不仅会在文章详情中作为标题的背景显示（同时自动缩放和剪裁），也会以缩略图的形式出现在文章列表中。

## 构建

至此，网站已经准备好。 要构建出静态页面，我们需要把所写文章的 `draft` 属性改为 `false`，然后运行 `hugo` 命令:

```sh
$ hugo

                   | EN  
-------------------+-----
  Pages            | 14  
  Paginator pages  |  0  
  Non-page files   |  0  
  Static files     |  6  
  Processed images |  0  
  Aliases          |  1  
  Sitemaps         |  1  
  Cleaned          |  0  

Total in 48 ms
```

生成的内容将出现在 `./public` 目录下。将其中内容发布到服务器便大功告成了。

## 总结

本文记录了我对Hugo两个小时边学习边实践的过程，把它作为此网站的第一篇文章。

总体而言，Hugo 在易用和灵活之间作了很好的平衡。 新手可以快速上手；如果想作深度定制，也完全支持。用Hugo建站的体验使我回忆起了上世纪90年代刚建起个人主页的那些美好时光。

作为入门文章，本文没有涉及Hugo的一些高级特性。比如它的引以为傲的 [Shortcodes](https://gohugo.io/content-management/shortcodes/)，[Archetypes](https://gohugo.io/content-management/archetypes/)，[模板机制](https://gohugo.io/templates/) 等等。相信这些在以后的实践中也能用得到。

本文是我对 IPFS / Web3 学习和探索的起点。 下一步我会介绍如何把这个用Hugo建成的站点发布到IPFS上，向大家展示传说的IPFS也可以很容易上手，并且能与现存的Web体系合谐共存。

敬请期待！
