前言

上一篇正经发布的博客还是在 2016 年 2 月 距离现在过去了 6 年,真的是时光荏苒。回想起从 2013 年起到现在,我曾经注册过许多域名,其中包括 kunr.merakume.comrya.somirai.run 等等……始终在使用的也只有第二个了,然后还能收到一些以前朋友的来访与告知域名更新也是挺感动的。

终于,克服了拖延症,将博客重新搭建了起来(其实这个博客的大概初设计稿完成在三年前),而且我才仅实现了一小部分。这次博客主要在 Hugo 且基于主题 PaperMod 的基础上进行的魔改,部署方案是通过 GitHub Actions 并部署在 Vercel 上。不得不说现在进行任何一个静态博客的发布,实在是太容易了。

Hugo

得益于 Hugo 是基于 golang 打包的二进制包,故我们可以很容易的在任何平台上使用,而不需要像 Hexo 一般安装 Node.js 的全环境并且安装 Hexo 的依赖。

安装 Hugo

你可以使用任何一个包管理环境,在 Windows 上你可以使用 scoop 这样安装 Hugo:

scoop install hugo

如果你是其他平台,可以参考此官方的 安装 Hugo 1 完成 Hugo 的安装。

简易使用指南

hugo new site demo
# 下载主题
git clone https://github.com/adityatelange/hugo-PaperMod themes/PaperMod --depth=1
echo 'theme = "PaperMod"' >> config.toml
hugo server -D # LiveReload 启动
hugo # 编译博客
# 新建文章
hugo new posts/my-first-post.md

# 新建页面
hugo new links.md 

主题配置

搜索功能的配置

搜索依赖于基于 JSON 的搜索,于是输出需要包含 JSON 的格式;同时通过配置 fuseOpts 可以对搜索的参数进行修改。

  outputs:
    home:
        - HTML
        - RSS
        - JSON # is necessary

  # for search
  # https://fusejs.io/api/options.html
  fuseOpts:
    isCaseSensitive: false
    shouldSort: true
    location: 0
    distance: 1000
    threshold: 0.4
    minMatchCharLength: 0
    keys: ["title", "permalink", "summary", "content"]

在对主题配置完成后,还需要新建搜索页面,

cat > content/search.md <<EOF
---
title: "搜索" # in any language you want
layout: "search" # is necessary
# url: "/archive"
# description: "Description for Search"
summary: "search"
placeholder: "键入搜索关键词"
---
EOF

链接自定义渲染

需要对站内外链接进行区分打开,可以通过 Hugo 的 Render Hook2 进行操作,文件位于主题目录下的 layouts/_default/_markup/render-link.html,内容大致如下:

<a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if strings.HasPrefix .Destination "http" }} target="_blank"{{ end }}>{{ .Text | safeHTML }}</a>

内容目录实现

内容目录 Hugo 有原生的实现,但是没有滚动指示的功能,于是便想办法实现一下; 比较有意思的一个实现是通过 IntersectionObserver3 来实现的可视化标题4

核心思路是通过“是否可视”来对目录元素进行一个点亮/熄灭,代码如下:

	const observer = new IntersectionObserver(entries => {
		entries.forEach(entry => {
			const id = entry.target.getAttribute('id');
			if (entry.intersectionRatio > 0) {
				document.querySelector(`nav li a[href="#${id}"]`).parentElement.classList.add('active');
			} else {
				document.querySelector(`nav li a[href="#${id}"]`).parentElement.classList.remove('active');
			}
		});
	});

	// Track all sections that have an `id` applied
	document.querySelectorAll('section[id]').forEach((section) => {
		observer.observe(section);
	});

但是这时就遇到了个问题,原文是对整个区域进行监听,但是我们 Hugo 生成的正文没有整块对应的 section,如果我们直接将 section[id] 改为 h1, h2, h3 的效果便是在标题与标题中间会产生“没有有效指示”的情况出现。

此时,解决方法有两种:

  1. 给标题标注区域;
  2. 顺序点亮标题。

本站使用了法二,因为改造成本非常低,首先将所有可视的标题点亮,然后仅保留第一个,则能解决上述问题。

entries.forEach(entry => {
  let href = `#${encodeURIComponent(entry.target.getAttribute('id')).toLocaleLowerCase()}`,
  link = this.links.find(l => l.getAttribute('href') === href)

  if (entry.isIntersecting && entry.intersectionRatio >= 1) {
    link.classList.add('is-visible')
    this.previousSection = entry.target.getAttribute('id')
  } else {
    link.classList.remove('is-visible')
  }

  this.highlightFirstActive()
})

部署

Vercel 部署

Vercel 的部署并不困难,他本身提供了 Hugo 的环境也提供了一份简易的说明文档5,需要注意的不过是定义 Hugo 版本,其中 0.92.2 为你所需要的版本号,如果没有指定 Vercel 默认的版本比较低,可能会遇到兼容性问题,我因此发了好几个 build 都没成功,看了 log 才注意到。

{
  "build": {
    "env": {
      "HUGO_VERSION": "0.92.2"
    }
  }
}

解决 Vercel 编译带草稿的问题

草稿文章在本地正常被隐藏,但是在 Vercel 被显示出来了。

问题出在 Vercel 的默认 Hugo 参数带 -D 意义为编译草稿文章,但是我们不需要,所以通过以下步骤可恢复正常:

  1. 定位到 https://vercel.com/USERNAME/PROJECT/settings/general;
  2. 找到 Build & Development Settings
  3. BUILD COMMAND 改成 hugo --gc

同步 Gitee(不推荐)

这里使用 GitHub Actions 做 Gitee Pages 的同步部署。

创建 GitHub Action Workflow

name: Sync

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Build hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: '0.92.2'
          extended: true

      - name: Sync to Gitee
        uses: wearerequired/git-mirror-action@master
        env:
          # 注意在 Settings->Secrets 配置 GITEE_RSA_PRIVATE_KEY
          SSH_PRIVATE_KEY: ${{ secrets.GITEE_RSA_PRIVATE_KEY }}
        with:
          # 注意替换为你的 GitHub 源仓库地址
          source-repo: git@github.com:doocs/leetcode.git
          # 注意替换为你的 Gitee 目标仓库地址
          destination-repo: git@gitee.com:Doocs/leetcode.git

      - name: Build Gitee Pages
        uses: yanglbme/gitee-pages-action@main
        with:
          # 注意替换为你的 Gitee 用户名
          gitee-username: 【用户名改我】
          # 注意在 Settings->Secrets 配置 GITEE_PASSWORD
          gitee-password: ${{ secrets.GITEE_PASSWORD }}
          # 注意替换为你的 Gitee 仓库,仓库名严格区分大小写,请准确填写,否则会出错
          gitee-repo: doocs/leetcode
          # 要部署的分支,默认是 master,若是其他分支,则需要指定(指定的分支必须存在)
          branch: main

配置密钥6

  1. 生成密钥,并且将其同步配置到 GitHub 与 Gitee;
  2. 将 GITEE_PASSWORD 与 GITEE_RSA_PRIVATE_KEY 配置到项目的环境变量;
  3. 提前做好 Gitee 的绑定手机、绑定微信与实名认证工作

运行

如果出现任何错误还请查看 yanglbme/gitee-pages-action错误解决方案