前言
上一篇正经发布的博客还是在 2016 年 2 月 距离现在过去了 6 年,真的是时光荏苒。回想起从 2013 年起到现在,我曾经注册过许多域名,其中包括 kunr.me、rakume.com 、rya.so、mirai.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 有原生的实现,但是没有滚动指示的功能,于是便想办法实现一下;
比较有意思的一个实现是通过 IntersectionObserver
3 来实现的可视化标题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
的效果便是在标题与标题中间会产生“没有有效指示”的情况出现。
此时,解决方法有两种:
- 给标题标注区域;
- 顺序点亮标题。
本站使用了法二,因为改造成本非常低,首先将所有可视的标题点亮,然后仅保留第一个,则能解决上述问题。
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
意义为编译草稿文章,但是我们不需要,所以通过以下步骤可恢复正常:
- 定位到
https://vercel.com/USERNAME/PROJECT/settings/general
; - 找到
Build & Development Settings
- 讲
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
- 生成密钥,并且将其同步配置到 GitHub 与 Gitee;
- 将 GITEE_PASSWORD 与 GITEE_RSA_PRIVATE_KEY 配置到项目的环境变量;
- 提前做好 Gitee 的绑定手机、绑定微信与实名认证工作
运行
如果出现任何错误还请查看 yanglbme/gitee-pages-action
的错误解决方案
。
-
https://gohugo.io/getting-started/quick-start/#step-1-install-hugo ↩︎
-
https://gohugo.io/getting-started/configuration-markup#render-hook-templates ↩︎
-
https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API ↩︎
-
https://www.bram.us/2020/01/10/smooth-scrolling-sticky-scrollspy-navigation/ ↩︎
-
https://github.com/yanglbme/gitee-pages-action#2-%E9%85%8D%E7%BD%AE%E5%AF%86%E9%92%A5 ↩︎