迁移博客到Hugo并使用GitHub Actions自动部署
本博客从2020年底使用 Gridea 进行部署,主要是看中 Gridea 在操作上的简易性,怎奈国内 GitHub 网络环境太差,Gridea 又不会走系统的代理,因此频繁出现程序假死或者编译的网站部分上传成功的问题。虽然我博客更新极慢,终究是维护体验不好再加上软件几乎不怎么更新了,随作罢,换成 Hugo + LoveIt 主题,并通过 GitHub Actions 进行自动部署。
本地环境
Hugo 安装
我是使用 Windows 下 Scoop 一键安装的,或者可以使用 Hugo 的安装包,然后手动配置环境变量。
scoop install hugo
检查安装结果:
hugo version
# hugo v0.88.1-5BC54738 windows/amd64 BuildDate=2021-09-04T09:39:19Z VendorInfo=gohugoio
新建一个博客仓库:
hugo new site BLOG_DIR
cd ./BLOG_DIR
因为我要使用 GitHub Actions 来自动部署,所以之后的操作需要先初始化 git,如果只是单纯的 Hugo 博客,可以暂时不设置。
# 初始化 git
git init
# 将 LoveIt 库作为 submodule,并在根目录 config.toml 中进行配置
git submodule add https://github.com/dillonzq/LoveIt.git themes/LoveIt
# 新建测试文章,并编辑
# 新建的的文章中都包含属性 draft: true,即草稿模式,更改为 false 才会被渲染
hugo new posts/hello.md
# 本地测试网站,http://localhost:1313,内容更新时会自动刷新
hugo serve
# 构建网站
hugo
我这里直接使用了 LoveIt 主题的完整配置,而非基础配置,比较长。
[params]
# LoveIt 主题版本
version = "0.2.X"
# 网站描述
description = "这是我的全新 Hugo 网站"
# 网站关键词
keywords = ["Theme", "Hugo"]
# 网站默认主题样式 ("light", "dark", "auto")
defaultTheme = "auto"
# 公共 git 仓库路径,仅在 enableGitInfo 设为 true 时有效
gitRepo = ""
# 哪种哈希函数用来 SRI, 为空时表示不使用 SRI
# ("sha256", "sha384", "sha512", "md5")
fingerprint = ""
# 日期格式
dateFormat = "2006-01-02"
# 网站图片, 用于 Open Graph 和 Twitter Cards
images = ["/logo.png"]
# 应用图标配置
[params.app]
# 当添加到 iOS 主屏幕或者 Android 启动器时的标题, 覆盖默认标题
title = "LoveIt"
# 是否隐藏网站图标资源链接
noFavicon = false
# 更现代的 SVG 网站图标, 可替代旧的 .png 和 .ico 文件
svgFavicon = ""
# Android 浏览器主题色
themeColor = "#ffffff"
# Safari 图标颜色
iconColor = "#5bbad5"
# Windows v8-10磁贴颜色
tileColor = "#da532c"
# 搜索配置
[params.search]
enable = true
# 搜索引擎的类型 ("lunr", "algolia")
type = "lunr"
# 文章内容最长索引长度
contentLength = 4000
# 搜索框的占位提示语
placeholder = ""
# 最大结果数目
maxResultLength = 10
# 结果内容片段长度
snippetLength = 50
# 搜索结果中高亮部分的 HTML 标签
highlightTag = "em"
# 是否在搜索索引中使用基于 baseURL 的绝对路径
absoluteURL = false
[params.search.algolia]
index = ""
appID = ""
searchKey = ""
# 页面头部导航栏配置
[params.header]
# 桌面端导航栏模式 ("fixed", "normal", "auto")
desktopMode = "fixed"
# 移动端导航栏模式 ("fixed", "normal", "auto")
mobileMode = "auto"
# 页面头部导航栏标题配置
[params.header.title]
# LOGO 的 URL
logo = ""
# 标题名称
name = ""
# 你可以在名称 (允许 HTML 格式) 之前添加其他信息, 例如图标
pre = ""
# 你可以在名称 (允许 HTML 格式) 之后添加其他信息, 例如图标
post = ""
# 是否为标题显示打字机动画
typeit = false
# 页面底部信息配置
[params.footer]
enable = true
# 自定义内容 (支持 HTML 格式)
custom = ''
# 是否显示 Hugo 和主题信息
hugo = true
# 是否显示版权信息
copyright = true
# 是否显示作者
author = true
# 网站创立年份
since = 2019
# ICP 备案信息,仅在中国使用 (支持 HTML 格式)
icp = ""
# 许可协议信息 (支持 HTML 格式)
license = '<a rel="license external nofollow noopener noreffer" href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank">CC BY-NC 4.0</a>'
# Section (所有文章) 页面配置
[params.section]
# section 页面每页显示文章数量
paginate = 20
# 日期格式 (月和日)
dateFormat = "01-02"
# RSS 文章数目
rss = 10
# List (目录或标签) 页面配置
[params.list]
# list 页面每页显示文章数量
paginate = 20
# 日期格式 (月和日)
dateFormat = "01-02"
# RSS 文章数目
rss = 10
# 主页配置
[params.home]
# RSS 文章数目
rss = 10
# 主页个人信息
[params.home.profile]
enable = true
# Gravatar 邮箱,用于优先在主页显示的头像
gravatarEmail = ""
# 主页显示头像的 URL
avatarURL = "/images/avatar.png"
# 主页显示的网站标题 (支持 HTML 格式)
title = ""
# 主页显示的网站副标题
subtitle = "这是我的全新 Hugo 网站"
# 是否为副标题显示打字机动画
typeit = true
# 是否显示社交账号
social = true
# 免责声明 (支持 HTML 格式)
disclaimer = ""
# 主页文章列表
[params.home.posts]
enable = true
# 主页每页显示文章数量
paginate = 6
# 被 params.page 中的 hiddenFromHomePage 替代
# 当你没有在文章前置参数中设置 "hiddenFromHomePage" 时的默认行为
defaultHiddenFromHomePage = false
# 作者的社交信息设置
[params.social]
GitHub = "xxxx"
Linkedin = ""
Twitter = "xxxx"
Instagram = "xxxx"
Facebook = "xxxx"
Telegram = "xxxx"
Medium = ""
Gitlab = ""
Youtubelegacy = ""
Youtubecustom = ""
Youtubechannel = ""
Tumblr = ""
Quora = ""
Keybase = ""
Pinterest = ""
Reddit = ""
Codepen = ""
FreeCodeCamp = ""
Bitbucket = ""
Stackoverflow = ""
Weibo = ""
Odnoklassniki = ""
VK = ""
Flickr = ""
Xing = ""
Snapchat = ""
Soundcloud = ""
Spotify = ""
Bandcamp = ""
Paypal = ""
Fivehundredpx = ""
Mix = ""
Goodreads = ""
Lastfm = ""
Foursquare = ""
Hackernews = ""
Kickstarter = ""
Patreon = ""
Steam = ""
Twitch = ""
Strava = ""
Skype = ""
Whatsapp = ""
Zhihu = ""
Douban = ""
Angellist = ""
Slidershare = ""
Jsfiddle = ""
Deviantart = ""
Behance = ""
Dribbble = ""
Wordpress = ""
Vine = ""
Googlescholar = ""
Researchgate = ""
Mastodon = ""
Thingiverse = ""
Devto = ""
Gitea = ""
XMPP = ""
Matrix = ""
Bilibili = ""
Email = "[email protected]"
RSS = true #
# 文章页面配置
[params.page]
# 是否在主页隐藏一篇文章
hiddenFromHomePage = false
# 是否在搜索结果中隐藏一篇文章
hiddenFromSearch = false
# 是否使用 twemoji
twemoji = false
# 是否使用 lightgallery
lightgallery = false
# 是否使用 ruby 扩展语法
ruby = true
# 是否使用 fraction 扩展语法
fraction = true
# 是否使用 fontawesome 扩展语法
fontawesome = true
# 是否在文章页面显示原始 Markdown 文档链接
linkToMarkdown = true
# 是否在 RSS 中显示全文内容
rssFullText = false
# 目录配置
[params.page.toc]
# 是否使用目录
enable = true
# 是否保持使用文章前面的静态目录
keepStatic = true
# 是否使侧边目录自动折叠展开
auto = true
# 代码配置
[params.page.code]
# 是否显示代码块的复制按钮
copy = true
# 默认展开显示的代码行数
maxShownLines = 10
# KaTeX 数学公式
[params.page.math]
enable = true
# 默认块定界符是 $$ ... $$ 和 \\[ ... \\]
blockLeftDelimiter = ""
blockRightDelimiter = ""
# 默认行内定界符是 $ ... $ 和 \\( ... \\)
inlineLeftDelimiter = ""
inlineRightDelimiter = ""
# KaTeX 插件 copy_tex
copyTex = true
# KaTeX 插件 mhchem
mhchem = true
# Mapbox GL JS 配置
[params.page.mapbox]
# Mapbox GL JS 的 access token
accessToken = ""
# 浅色主题的地图样式
lightStyle = "mapbox://styles/mapbox/light-v9"
# 深色主题的地图样式
darkStyle = "mapbox://styles/mapbox/dark-v9"
# 是否添加 NavigationControl
navigation = true
# 是否添加 GeolocateControl
geolocate = true
# 是否添加 ScaleControl
scale = true
# 是否添加 FullscreenControl
fullscreen = true
# 文章页面的分享信息设置
[params.page.share]
enable = true
Twitter = true
Facebook = true
Linkedin = false
Whatsapp = true
Pinterest = false
Tumblr = false
HackerNews = false
Reddit = false
VK = false
Buffer = false
Xing = false
Line = true
Instapaper = false
Pocket = false
Digg = false
Stumbleupon = false
Flipboard = false
Weibo = true
Renren = false
Myspace = true
Blogger = true
Baidu = false
Odnoklassniki = false
Evernote = true
Skype = false
Trello = false
Mix = false
# 评论系统设置
[params.page.comment]
enable = true
# Disqus 评论系统设置
[params.page.comment.disqus]
#
enable = false
# Disqus 的 shortname,用来在文章中启用 Disqus 评论系统
shortname = ""
# Gitalk 评论系统设置
[params.page.comment.gitalk]
#
enable = false
owner = ""
repo = ""
clientId = ""
clientSecret = ""
# Valine 评论系统设置
[params.page.comment.valine]
enable = false
appId = ""
appKey = ""
placeholder = ""
avatar = "mp"
meta= ""
pageSize = 10
lang = ""
visitor = true
recordIP = true
highlight = true
enableQQ = false
serverURLs = ""
# emoji 数据文件名称, 默认是 "google.yml"
# ("apple.yml", "google.yml", "facebook.yml", "twitter.yml")
# 位于 "themes/LoveIt/assets/data/emoji/" 目录
# 可以在你的项目下相同路径存放你自己的数据文件:
# "assets/data/emoji/"
emoji = ""
# Facebook 评论系统设置
[params.page.comment.facebook]
enable = false
width = "100%"
numPosts = 10
appId = ""
languageCode = "zh_CN"
# Telegram Comments 评论系统设置
[params.page.comment.telegram]
enable = false
siteID = ""
limit = 5
height = ""
color = ""
colorful = true
dislikes = false
outlined = false
# Commento 评论系统设置
[params.page.comment.commento]
enable = false
# Utterances 评论系统设置
[params.page.comment.utterances]
enable = false
# owner/repo
repo = ""
issueTerm = "pathname"
label = ""
lightTheme = "github-light"
darkTheme = "github-dark"
# 第三方库配置
[params.page.library]
[params.page.library.css]
# someCSS = "some.css"
# 位于 "assets/"
# 或者
# someCSS = "https://cdn.example.com/some.css"
[params.page.library.js]
# someJavascript = "some.js"
# 位于 "assets/"
# 或者
# someJavascript = "https://cdn.example.com/some.js"
# 页面 SEO 配置
[params.page.seo]
# 图片 URL
images = []
# 出版者信息
[params.page.seo.publisher]
name = ""
logoUrl = ""
# TypeIt 配置
[params.typeit]
# 每一步的打字速度 (单位是毫秒)
speed = 100
# 光标的闪烁速度 (单位是毫秒)
cursorSpeed = 1000
# 光标的字符 (支持 HTML 格式)
cursorChar = "|"
# 打字结束之后光标的持续时间 (单位是毫秒, "-1" 代表无限大)
duration = -1
# 网站验证代码,用于 Google/Bing/Yandex/Pinterest/Baidu
[params.verification]
google = ""
bing = ""
yandex = ""
pinterest = ""
baidu = ""
# 网站 SEO 配置
[params.seo]
# 图片 URL
image = ""
# 缩略图 URL
thumbnailUrl = ""
# 网站分析配置
[params.analytics]
enable = false
# Google Analytics
[params.analytics.google]
id = ""
# 是否匿名化用户 IP
anonymizeIP = true
# Fathom Analytics
[params.analytics.fathom]
id = ""
# 自行托管追踪器时的主机路径
server = ""
# Cookie 许可配置
[params.cookieconsent]
enable = true
# 用于 Cookie 许可横幅的文本字符串
[params.cookieconsent.content]
message = ""
dismiss = ""
link = ""
# 第三方库文件的 CDN 设置
[params.cdn]
# CDN 数据文件名称, 默认不启用
# ("jsdelivr.yml")
# 位于 "themes/LoveIt/assets/data/cdn/" 目录
# 可以在你的项目下相同路径存放你自己的数据文件:
# "assets/data/cdn/"
data = ""
# 兼容性设置
[params.compatibility]
# 是否使用 Polyfill.io 来兼容旧式浏览器
polyfill = false
# 是否使用 object-fit-images 来兼容旧式浏览器
objectFit = false
# Hugo 解析文档的配置
[markup]
# 语法高亮设置
[markup.highlight]
codeFences = true
guessSyntax = true
lineNos = true
lineNumbersInTable = true
# false 是必要的设置
# (https://github.com/dillonzq/LoveIt/issues/158)
noClasses = false
# Goldmark 是 Hugo 0.60 以来的默认 Markdown 解析库
[markup.goldmark]
[markup.goldmark.extensions]
definitionList = true
footnote = true
linkify = true
strikethrough = true
table = true
taskList = true
typographer = true
[markup.goldmark.renderer]
# 是否在文档中直接使用 HTML 标签
unsafe = true
# 目录设置
[markup.tableOfContents]
startLevel = 2
endLevel = 6
# 作者配置
[author]
name = "xxxx"
email = ""
link = ""
# 网站地图配置
[sitemap]
changefreq = "weekly"
filename = "sitemap.xml"
priority = 0.5
# Permalinks 配置
[Permalinks]
# posts = ":year/:month/:filename"
posts = ":filename"
# 隐私信息配置
[privacy]
# Google Analytics 相关隐私 (被 params.analytics.google 替代)
[privacy.googleAnalytics]
# ...
[privacy.twitter]
enableDNT = true
[privacy.youtube]
privacyEnhanced = true
# 用于输出 Markdown 格式文档的设置
[mediaTypes]
[mediaTypes."text/plain"]
suffixes = ["md"]
# 用于输出 Markdown 格式文档的设置
[outputFormats.MarkDown]
mediaType = "text/plain"
isPlainText = true
isHTML = false
# 用于 Hugo 输出文档的设置
[outputs]
#
home = ["HTML", "RSS", "JSON"]
page = ["HTML", "MarkDown"]
section = ["HTML", "RSS"]
taxonomy = ["HTML", "RSS"]
taxonomyTerm = ["HTML"]
GitHub 仓库
如果上述操作不报错的话,就已经获得一个本地的静态博客了,接下来去 GitHub 上准备两个仓库,一个是私有仓库 (private),用于存放 Hugo 源码,另一个是 GitHub Pages 仓库用于存放编译好的静态网页。在账户设置里申请一个 token,然后记下 token 并填写在私有仓库的 设置 - secrets
里,我这里起名为 HUGO
。
-
是账户设置,而非仓库设置,Setting - Developer Settings - Personal access tokens
-
生成 token 时需要将 repo 和 admin:repo_hook 全部勾选上
-
token 可以设置有效期,最长为永久
操作完成之后将本地文件上传至 GitHub 的私人仓库上。
# 新建 .gitignore 并忽略 public 文件夹
touch .git
# 关联远程私有仓库
git remote add origin 私有仓库
# 上传
git add .
git commit -m 'first commit'
git push
GitHub Actions
我这里的 Hugo 文件全部上传到了私有仓库的 master 分支上,然后在本地新建一个 GitHub Actions 文件 .github/workflows/deploy.yml
,填入以下内容:
name: Hugo blog # 名字自取
on:
push:
branches:
- master # 这里的意思是当 master分支发生push的时候,运行下面的jobs
jobs:
deploy: # 任务名自取
runs-on: ubuntu-18.04 # 在什么环境运行任务
steps:
- uses: actions/checkout@v2 # 引用actions/checkout这个action,与所在的github仓库同名
with:
submodules: true # Fetch Hugo themes (true OR recursive) 获取submodule主题
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
- name: Setup Hugo # 步骤名自取
uses: peaceiris/actions-hugo@v2 # hugo官方提供的action,用于在任务环境中获取hugo
with:
hugo-version: 'latest' # 获取最新版本的hugo
# extended: true
- name: Build
run: hugo --minify # 使用hugo构建静态网页
- name: Deploy
uses: peaceiris/actions-gh-pages@v3 # 一个自动发布github pages的action
with:
# github_token: ${{ secrets.GITHUB_TOKEN }} 该项适用于发布到源码相同repo的情况,不能用于发布到其他repo
external_repository: TianYang-TY/TianYang-TY.github.io # 发布到哪个repo
personal_token: ${{ secrets.HUGO }} # 发布到其他repo需要提供上面生成的personal access token
publish_dir: ./public # 注意这里指的是要发布哪个文件夹的内容,而不是指发布到目的仓库的什么位置,因为hugo默认生成静态网页到public文件夹,所以这里发布public文件夹里的内容
publish_branch: master # 发布到哪个branch
Line 6:注意确定分支名称
Line 30:修改为自己的 GitHub Pages 库
Line 31:secrets.HUGO
对应之前设置的 secrets 名称
将新生成的文件也上传到 GitHub 私有仓库中,就会开始自动部署。
LoveIt 主题设置
LoveIt 主题还提供了一个
URL 自定义
默认的文章全部以 domain . com/filename.html
形式访问,为了保持与原 Gridea 生成的文章一样的路径,不扰乱搜索引擎的现有结果,顺便治疗强迫症,我将其修改为 domain . com/post/filename.html
[Permalinks]
# 阳间格式 posts/filename
posts = ":sections/:filename"
# 为了与 Gridea 相同
posts = "post/:filename"
百度统计
百度统计需要修改两个位置
-
config.toml
[params.analytics] enable = true # 默认为 false # Baidu Analytics # 百度统计 [params.analytics.baidu] id = "" # id 来自于百度统计网站
-
复制
\themes\LoveIt\layouts\partials\plugin\analytics.html
到\layouts\partials\plugin\analytics.html
,然后添加以下内容:{{- /* Baidu Analytics */ -}} {{- with $analytics.baidu.id -}} <script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?{{ . }}"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script> {{- end -}}
404 界面
如果要自定义 404 界面,只需要把 404.html
放在根目录 /layouts
下。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Page Not Found</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
display: flex;
flex-direction: column;
height: 100vh;
text-align: center;
}
.box {
flex: 1;
display: flex;
justify-content: center;
flex-direction: column;
}
.number {
font-size: 100px;
color: #666;
font-weight: bold;
}
.text {
font-size: 14px;
margin: 24px;
color: #333;
}
.btn-container {
display: flex;
justify-content: center;
}
.btn {
padding: 8px 24px;
display: inline-block;
text-decoration: none;
background: #fff;
border: 2px solid #efefef;
color: #333;
margin: 24px;
border-radius: 20px;
cursor: pointer;
display: flex;
align-items: center;
}
.footer {
padding: 16px;
border-top: 1px solid #efefef;
color: #777;
font-weight: lighter;
}
.footer a {
text-decoration: none;
font-weight: bold;
color: #000;
}
</style>
</head>
<body>
<div class="box">
<div class="number">4 0 4</div>
<div class="text">
<h2>UH OH! You're lost.</h2>
</div>
<div class="btn-container">
<a class="btn" id="back">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" style="margin-right: 8px;">
<path fill="none" d="M0 0h24v24H0z"/>
<path d="M5.828 7l2.536 2.536L6.95 10.95 2 6l4.95-4.95 1.414 1.414L5.828 5H13a8 8 0 1 1 0 16H4v-2h9a6 6 0 1 0 0-12H5.828z"/>
</svg>
HOME
</a>
</div>
</div>
<footer class="footer">
Copyright © 2019-2020 Yang Tian. All rights reserved.
</footer>
<script>
var back = document.getElementById('back')
back.onclick = function() { window.location.assign("https://yangt.me"); }
</script>
</body>
</html>
参考链接
Hugo系列(3.1) - LoveIt主题美化与博客功能增强 · 第二章 - Yulin Lewis’ Blog (lewky.cn)
主题文档 - 基本概念 - LoveIt (hugoloveit.com)
How to create url for /blog/ instead of /posts/? - support - HUGO (gohugo.io)
- Author: Yang
- Link: https://yangt.me/posts/hugo-blog-with-github-actions/
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.