转载https://www.waynerv.com/posts/setup-blog-with-hugo-and-github-pages/

作为一个已经入行了一年多的(老)技术人,维护一个看得过去的个人博客是很有必要的。

刚学编程的时候,还开源过一个基于 Flask 和 MongoDB 的博客项目,但后面就没怎么使用和维护了,除开主观上的懒,还因为:

  • 自建博客绕不开主机和域名,这是一笔持续的经济成本。国内的主机往往是第一年割肉第二年宰猪,国外的主机访问延迟很高。
  • 国内主机更麻烦的是还需要定期备案,第一个博客就是因为备案到期中断了。
  • 博客功能的实现技术难度不大,开始还有一些新鲜感,有了工作经验后就很难有兴趣继续维护了。

刚好最近有写一些文章的打算,决定找个简单、省事(最后发现并没有)且不花钱的路子把博客再搞起来,一番研究后,选择了生成静态站点发布到 GitHub Pages 的方案。

工作流

整个方案的流程大致如下:

  1. 用 Markdown 格式写作文章。
  2. 使用生成器将 markdown 文件转换成静态站点。
  3. 将生成的站点内容推送到 GitHub 并发布。

写 markdown 没啥好说的,什么编辑器都可以,我一直用的是 Typora。

静态站点生成器我选择了 Hugo,原因是最近刚好在学 Go,此外还有 Gatsby、Jekyll、Hexo 等很多选项。

接下来要做的工作是生成静态站点并通过 GitHub Pages 发布。

生成静态站点

使用 Hugo 生成静态博客站点非常简单,具体的步骤和用法可以参考官方文档的 Quick Start。下面简单介绍下整个过程:

  1. 安装 Hugo。macOS 下可以直接使用 homebrew 安装:brew install hugo。

  2. 创建一个新的站点。这会生成一个特定目录结构的项目文件夹,用来维护所有的站点内容。假设我们想把它命名为 hugo-blog,则使用以下命令创建并切换到该目录,后续的操作和命令都会在这个根目录下执行:

1
2
    hugo new site hugo-blog
    cd hugo-blog
  1. 安装一个主题。这一步是必需的,否则会因为缺少基础模板无法生成站点。安装主题有 3 种方式,以 eureka 主题为例:

    • 直接下载主题的压缩文件,将解压得到的文件夹重命名为主题名称 eureka 放到 themes/目录下。
    • 通过 git submodule 安装:
    1
    2
    
        git init
        git submodule add https://github.com/wangchucheng/hugo-eureka.git themes/eureka
    
    • 通过 Hugo Modules 安装(这种方式要求本机安装有 Go 1.12 及以上版本,且只有部分主题支持): <module_name> 并不重要,随便起个名字就行。 安装后需要启用主题,方法是将主题名称写入到根目录下的默认配置文件 config.yml 中: 如果是通过 Hugo Modules 安装,需要把主题名称替换成模块名称:
  2. 添加一篇文章。可以直接在 content/posts 目录下创建 markdown 文件,但需要手动写入一些元信息,因此推荐使用 Hugo 自带的命令:hugo new posts/my-first-post.md,添加的文件会以如下元信息开头:

    在下方接着写入文章内容即可。注意此时该文件为草稿状态,写作完成后需要改成 draft: false 才能部署。

  3. 启动 Hugo 预览服务器。Hugo 可以启动一个 Web 服务器,同时构建站点内容到内存中并在检测到文件更改后重新渲染,方便我们在开发环境实时预览对站点所做的更改。

    添加 -D 选项以输出草稿状态的文章,执行成功后可以通过 http://localhost:1313/ 访问站点。

  4. 自定义主题配置。站点的配置项默认保存在根目录的 config.toml 文件中,配置项较多时通常会用主题提供的预设配置文件来替换该文件,还可以通过 config 目录加多个文件的方式来组织配置。默认配置文件如下:

    这一步应该是整个过程中最麻烦也是最容易出问题的一步,视乎你选择的主题与想要的功能不同,需要自定义的配置项也不同,数量从几个到上百个不等。有些主题会有详细的文档解释配置过程,有些则一笔带过只能自己去摸索,配置较多时相互间可能还有依赖关系,最好更改一个配置就刷新一次页面确认下结果。 建议起步时一切从简,花大把时间搞各种花里胡哨的样式和功能,还不如多写几篇文章。

  5. 构建静态页面。站点配置成我们理想的效果之后就可以构建静态页面了:

    添加 -D 选项可以在结果中包括草稿内容,默认情况下静态页面会输出到根目录下的 public 文件夹中。

    (#通过-github-pages-发布)通过 GitHub Pages 发布

    这一步 Hugo 的官方文档同样在 Host on GitHub 中进行了详细的介绍,并且还很贴心的提供了自动化操作的 Shell 脚本。

    有两种方式:

  6. 通过个人主页发布:必须创建一个 <USERNAME>.github.io 仓库来托管生成的静态内容,发布后的域名为 https://<USERNAME>.github.io。

  7. 通过项目主页发布:可以随意创建 <PROJECT_NAME> 仓库,发布后的域名为 https://<USERNAME>.github.io/<PROJECT_NAME>。

    视选择的发布方式不同,我们需要将 config.yml 中的 baseUrl 设置为不同的值。

    通过个人主页发布

    建议非特殊情况下使用第 1 种方式,原因是许多主题都不能很好的支持第 2 种,具体来说是将 config.toml 的 baseURL 设置为含子路径的地址时,不能正确的处理所有资源的构建位置。我尝试了 3 个主题,均遭遇了不同的问题:

  • eureka: 构建失败,提示 :

    1
    
    Error: Error building site: POSTCSS: failed to transform "css/eureka.css" (text/css): resource "css/waynerv.github.io/css/eureka.css_fc3f76d7bee2760c3a903059afc3d9b2" not found in file cache```
    
  • LoveIt: 构建成功,但除主页以外的文章、分类和标签的页面均提示 404。

  • MemE: 构建成功,但文章中插入的图片加载 404(放在同一文件夹的 favicon 却能正常展示)。

    这个问题我在 eureka 项目提交了 issue,开发者回复可能是 Hugo 本身的机制所导致,并已经在 Hugo 论坛中提出了此问题,有兴趣的可以关注后续进展。

    发布步骤

  1. 在 GitHub 创建个人主页仓库,仓库名称必须设置为 <USERNAME>.github.io,这个仓库仅存放生成的静态内容。

  2. 在 GitHub 创建一个项目仓库 hugo-blog 并添加为我们本地项目文件夹的远程仓库。这个仓库用来维护站点配置和原始的文章内容。

  3. 假设我们在已经通过上文的步骤在 public 文件夹中生成了想发布的静态内容,运行:

    在 public 目录中创建一个 git 子模块,之后这个目录将以 https://github.com/&lt;USERNAME&gt;/&lt;USERNAME&gt;.github.io 作为远程仓库。

  4. 确保配置文件中的 baseUrl 已经设置为了 <USERNAME>.github.io。

  5. Hugo 为我们接下来的部署操作提供了一个自动化的 Shell 脚本:

    将如上内容保存到 deploy.sh 文件中,并执行 chmod +x deploy.sh 为其添加可执行权限。接着执行部署脚本: ./deploy.sh

    大功告成!稍等几分钟就可以在 https://.github.io 看到我们的个人博客了。

    通过 GitHub Actions 自动部署

    目前我们的「创作-发布」流程如下:

  6. 在项目仓库编辑原始内容并进行版本管理。

  7. 执行自动脚本生成静态站点并推送到个人主页仓库完成发布。

    这套流程已经很流畅,但还有一些改进空间:我们可以使用 GitHub Actions,在每次向远程的项目仓库推送原始内容更改时自动执行第 2 步进行发布。

    GitHub 上有许多这类自动化部署任务的开源 Actions 项目,我们选择了其中一个简单易用的 GitHub Actions for Hugo。具体的操作步骤截图和详细配置项可以查看该项目的 README。下面简单介绍下配置过程:

  8. 在项目文件夹中添加目录和文件:.github/workflows/gh-pages.yml,gh-pages.yml 文件内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
name: github pages
    on:
      push:
        branches:
          - main  # 每次推送到 main 分支都会触发部署任务
    jobs:
      deploy:
        runs-on: ubuntu-18.04
        steps:
          - uses: actions/checkout@v2
            with:
              submodules: true  # Fetch Hugo themes (true OR recursive)
              fetch-depth: 0    # Fetch all history for .GitInfo and .Lastmod
          - name: Setup Hugo
            uses: peaceiris/actions-hugo@v2
            with:
              hugo-version: '0.79.1'
              extended: true
          - name: Build
            run: hugo --minify
          - name: Deploy
            uses: peaceiris/actions-gh-pages@v3
            with:
              deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
              external_repository: &lt;USERNAME&gt;/&lt;USERNAME&gt;.github.io  # 替换成上文所创建的个人主页仓库
              publish_branch: main
              publish_dir: ./public
这个文件所定义的 workflow 基于项目仓库运行,但我们需要将运行过程生成的静态文件推送到个人主页仓库 &lt;USERNAME&gt;.github.io 完成发布,因此在 Deploy 任务中按照文档的 [Deploy to external repository external_repository](https://github.com/peaceiris/actions-gh-pages#%EF%B8%8F-deploy-to-external-repository-external_repository) 一节做了专门的配置。
  1. 在本地生成 SSH 部署密钥:

  2. 在 GitHub 分别进入项目仓库和个人主页仓库的 Settings 页面:

    • 将公钥 gh-pages.pub 作为 Secret 添加到项目仓库,并设置 Name 为 ACTIONS_DEPLOY_KEY。

      • 将私钥 gh-pages 作为 Deploy Key 添加到个人主页仓库,并设置为 Allow write access。

接下来我们测试一下效果。

在本地做一些更改,预览效果后提交并推送,然后在项目仓库的 GitHub Actions 页面检查相应的 workflow 是否运行成功。不出意外的话,很快个人主页仓库将新增一个由该 workflow 创建的提交,访问个人博客页面也会发现页面已经更新。

个人体验

由于先后选择的 3 个主题均遭遇了上述发布地址不能包含子路径的问题,我在基本按照官方文档操作的前提下,依然花了超过 10 个小时才把博客上线,浪费了很多时间在配置主题以及寻找问题的解决方案上。本以为选择了一个简单快捷的省心方案,结果还是免不了过程的一顿踩坑和折腾。

虽然搭建博客的流程不算省心,但我所遇到的这些问题也算是个例。一切准备就绪后,我们可以像写代码一样写博客,对文章修改提交即自动发布,也不需要考虑博客的样式、后台功能及主机维护等问题,对提升写作效率会有所帮助,可以省下来很多的时间和精力,综合来看体验还是不错的。