博客从 Hexo 迁移到 Hugo 的过程
2023年8月4日 · 6311 字 · 13 分钟 · #好玩系列
从今天开始,博客进入 2.0 版本。相比 1.0 版本,有了很多的新东西。
- 换了名字,这是我一直想做的事;
- 主题更清爽,Hexo 是简洁,但颜值一般;
- 新增评论、留言、赞助等功能;
- 整体结构更加简洁,更易修改。
以此总结一下在更换过程中遇到的问题,同时补充针对 guangzhengli/hugo-theme-ladder的修改记录,方便查阅。
本文并非从 0 到 1 的记录,所以不会提供很详细的截图;想详细了解的可以根据温中资料查阅,或者充分利用搜索引擎、AI 等产品哈;截图相对比较费时,我就偷个懒。
为什么想换
如果是「爱好折腾」占 70% ,那剩下 30% 一定是真需要换的理由。哈哈
现状:
- 旧博客的主题是 5.X 版本,目前最新 8.X 版本,如果要升级,需要调整的内容太多,我曾两次尝试,均以失败告终,还是选择了放弃。
- 旧的博客用了很长一段时间,期间改了不少的东西,我甚至忘记改过什么,每次调整都很麻烦,积累了太多的「bug」就会带来很多新「bug」,所以一直保持现状。
- 很多功能都缺失,比如留言、评论等;如果在原来基础上加的话,根据「第二条」阻力过大。
- 从 2016 年 - 2023 年,审美确实疲劳,换个好看一点的不过分吧?
机缘巧合,看到了 @GuangzhengLi 向量数据库文章,发现了这个 Blog 的主题是我喜欢的风格,非常简单明了,于是就有了换博客的想法。
哦,对了,1.0 版本我是和 Jason,独立开发者,自由职业者 | Jason 学习的。
迁移过程
了解新的框架和主题
从原理上来说,Hexo 和 Hugo 同属一种静态博客,写 Markdown 文件就可以完成部署,这是我为什么喜欢用 Hexo 的原因之一,在我能力范围内,它做到了足够简单;文件存储方式简单,部署方式简单。同样,Hugo 与它同理;但是我并没有实际安装和部署过,也是从头开始。好在 @GuangzhengLi 写了《如何 30 分钟搭建一套完整独立博客》 的文章,由于我没有安装过 Hugo ,所以也结合了 @Elizen 的 《使用 Hugo 从 0 到 1 搭建个人博客》 。此次能完成迁移,这两篇文章起到了至关重要的作用。
注册账号等流程我就省略了,可以参考 @Elizen 的文章,更详细。
第一步,先完成 demo 版的部署,快速找到「成就感」。访问 guangzhengli/hugo-ladder-exampleSite ,然后根据 README.md 就可以快速拥有一个线上的博客了。但是,但是,这里有一个小的问题 🙋♂️,我踩的第一个坑;流程并不是按照该文档说明的那样简单,在 Action
的时候就出现报错,具体如下:
Push the commit or tag
/usr/bin/git push origin gh-pages
remote: Permission to username/username.github.io.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/username/username.github.io.git/': The requested URL returned error: 403
Error: Action failed with "The process '/usr/bin/git' failed with exit code 128"
我通过 ChatGPT 问了很久,都没有找到答案,最后通过 Google 搜索,3s 就解决了问题。ChatGPT 让我配置权限,或者检查是否存在对应分支等。搜索的关键词是 https://github.com/ad-m/github-push-action/issues/96
,结果页第一个链接就可以解决,解决方案参见:remote: Permission to git denied to github-actions[bot]. · Issue #96 · ad-m/github-push-action,至此第一步已经完成。
这里也让我有非常大的收获:最近长期依赖 ChatGPT 等 AI 工具,导致我对搜索引擎使用频次大幅下降;两者的区别很大,前者类似我提出问题获得了一个需要我验证的答案,然后来回测试,这个过程我会越来越相信 AI ,而忘记了「思考」,成为了一个不需思考的执行者;后者我需要辨别,搜索结果页有很多的答案,我可以看到谁使用了什么方法达到了什么结果,对我来说是否合适?这个过程我需要判断和记忆,而非简单的执行。所以,后续我还是需要结合搜索引擎来寻求答案。
没有说 ChatGPT 不好用的意思,在后续的步骤,它起到了非常重要的作用。
第二步,本地安装环境,将 demo 部署到本地。这里就需要用到 @Elizen 的入门文章了,步骤也比较简单,会涉及到 Git 操作、版本兼容、网络等问题,一般搜索都可以解决,不再赘述啦。
准备定制化修改
第一步,先熟悉目录结构和配置文件(根目录下的config.yml
)。这个非常重要,因为所有的修改都是基于这个来的;如果不了解你想要修改的框架,后续将寸步难行。别慌,一个个来,先看配置文件。
baseURL: 'https://hugo-ladder.pages.dev' #修改为你的 https://username.github.io
homepage: 'https://hugo-ladder.pages.dev' #修改为你的 https://username.github.io
params:
brand: HOME # 修改默认的为自己网站的标志
avatarURL: /images/avatar.png #网站主页的照片信息,你可以在根目录 /static/images/ 里面替换成自己的照片
author: Hugo Ladder # 修改你自己的名字
authorDescription: # 修改对你自己的描述
info: # 修改对你自己网站描述
favicon: /images/avatar.png #网站的 icon,你可以在根目录 /static/images/ 里面替换成自己的照片
options:
showDarkMode: true # 是否支持黑暗模式
languages: # 如果你启用多语言,下面是中文展示
zh:
languageName: 中
author: Ladder 主题
authorDescription: 一个美观,快速并且专注于阅读的主题
info: 帮助开发者构建一个免费并且漂亮的博客网站,记录自己的思考并且提高自己的影响力
上面这个配置文件是 @GuangzhengLi 在安装文档提到了,备注已经写了,问题不大哈。我在此基础补充一份完整的配置文件介绍,这个是来自 ChatGPT 4.0 的总结。
👈 点击查看
- `baseURL`: 网站的基础URL,用于构造绝对URL。
- `title`: 网站的标题,常用于网站标题栏或头部。
- `theme`: 指定Hugo站点使用的主题。
- `license`: 网站使用的许可证类型。
- `licenselink`: 许可证的链接地址。
- `description`: 网站的描述信息。
- `homepage`: 网站主页的URL地址。
- `defaultContentLanguage`: 网站的默认内容语言。
- `googleAnalytics`: 用于Google Analytics的配置(值缺失)。
- `paginate`: 网站分页中每页的文章数量。
- `hasCJKLanguage`: 是否包括中日韩文字。
- `copyright`: 版权声明信息。
- `Author`: 作者信息字段,包括名字和电子邮件地址。
- `menu`: 定义主菜单的结构。
- `params`: 一系列自定义参数,具体解释如下:
- `brand`: 品牌名称。
- `avatarURL`: 作者头像的URL地址。
- `author`: 作者的名字。
- `authorDescription`: 作者的描述。
- `info`: 网站信息描述。
- `favicon`: 网站图标的URL地址。
- `options`: 一系列布尔选项,如是否显示深色模式,是否启用图片缩放等。
- `darkModeTheme`: 暗黑模式主题名称。
- `sponsors`: 赞助者相关信息,包括购买咖啡链接、微信和支付宝二维码等。
- `comments`: 评论系统的配置,包括giscus和utteranc的选项。
- `analytics`: 分析工具的配置,包括Google和Umami选项。
- `guestbook`: 留言板的标题和描述。
- `social`: 社交媒体链接和图标。
- `languages`: 网站的语言配置,可以定义不同语言下的特定内容。
- `taxonomies`: 自定义分类法的名称,例如系列和标签。
第二步,熟悉主题的目录(Hugo 目录前面文章都提到了),主题中主要熟悉 layouts
文件夹就行。具体如下:
- 主题文件是子模块,和 hugo-theme-ladder 保持同步,也可以用
git submodule update --remote --merge
命令进行手动更新。 - 自定义主题文件夹和主题文件结构一致,命名可以自己起;只是我为了能和主题更新保持同步,同时还能对主题进行修改,新建了主题;同时在
config.yml
配置好,就可以同时使用,渲染的时候自定义主题优先级高于原主题。 - 评论模块调整较少,
hugo-theme-ladder
提供了两种评论系统,我屏蔽了其中一个,使用giscus
。 - 公众模块,主要是调整网站开始时间。
- 网站首页没有做调整,这块就是访问网站的主页。
- 文章结构公共部分,调整很多,特别是
meta.html
后面延伸补充。 - 文章列表和主题也有调整,影响列表页和详情页。
- 一些特色的用法,参考guangzhengli/awesome-hugo-shortcodes就行,比较简单。
定制化修改
先确定目标,定制化修改的目的是不影响现有搜索引擎和访问体验。比如原来是 demochen.com/posts/122
可以访问详情页,现在只能 demochen.com/blog/122
就不符合要求,需要调整;除此之外就是个人的爱好方面调整了。
本人不太懂这些技术实现,可能有点傻傻的,但是需求是实现了,如果你有更好的方式欢迎评论补充👏
统一文章详情页的 URL
以前的文章详情页地址是demochen.com/posts/122
,现在主题的文件夹名不一样,是blog
了,意味着原来的就会404
,这是最不能接受的。调整方法如下:
- 将
layouts/
下的blog
改为posts
- 将
layouts/partials/
下的blog
改为posts
- 将
content/
下的blog
改为posts
- 将
config.yml
中的menu/main
下对应的文章url
改为/posts
- menu:
main:
- name: 文章
url: /posts
- 将
hemes/hugo-theme-ladder-my/layouts/_default/rss.xm
l 中blog
换成posts
,确保不影响 RSS
{{- $pctx := . -}}
{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
{{- $pages := slice -}}
{{- if or $.IsHome $.IsSection -}}
{{- $pages = (where (where $pctx.RegularPages ".Section" "posts") "Kind" "page") -}}
{{- else -}}
{{- $pages = (where (where $pctx.Pages ".Section" "posts") "Kind" "page") -}}
{{- end -}}
{{- $limit := .Site.Config.Services.RSS.Limit -}}
{{- if ge $limit 1 -}}
{{- $pages = $pages | first $limit -}}
{{- end -}}
{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
调整文章的ID
以前博客URL
是:域名 + posts + 文章ID,新的主题是 域名 + blog + 文章标题。所以尽管我们前面调整了 blog ,其实还是会 404
。原来文章的ID
是在文章yaml
中定义,字段是 abbrlink
,需要针对七调整。具体如下:
- 将原来的文章
Markdown
复制到content/posts
,同时通过VS code
将abbrlink
批量替换为slug
,因为Hugo
不支持原字段,所以需要调整。 - 最后在
config.yml
文件最后加上下列代码即可
permalinks:
posts: "/posts/:slug/"
调整博客 RSS 地址
Hugo
默认的 RSS
地址是以 域名+index.xml
结尾的,比如https://guangzhengli.com/index.xml
,我之前的博客的 RSS
地址是 atom.xml
结尾的,为了确保订阅的朋友还能收到更新,所以我需要调整。方法如下:
- 在
config.yml
文件最后加上下列代码(全文输出)
outputFormats:
RSS:
mediatype: application/rss
baseName: atom
notAlternative: true
调整目录显示调整
hugo-theme-ladder
默认每一篇文章都会显示目录,对于文章较短的我不希望显示目录,影响阅读体验。于是通过新增字段 no_toc
来判断是否显示目录,具体如下:
- 在
content/posts/
中不想显示目录的文件里添加no_toc: true
,默认显示目录,故不需要加代码 - 用下面的代码替换
themes/hugo-theme-ladder-my/layouts/partials/posts/toc.html
文件
{{ if or (not (isset .Params "no_toc")) (eq .Params.no_toc false) }}
{{ $.TableOfContents }}
{{ end }}
调整网站的开始运营时间
hugo-theme-ladder
默认是今年开始,对于迁移过来的人来说,不是很合理;于是在 themes/hugo-theme-ladder-my/layouts/partials/footer.html
文件中调整了代码,将 「2016 -」添加进去了。
<p>© 2016 - {{ now.Year }} <a href="{{ `` | absURL }}">{{ site.Title }}</a>
调整分类命名
Hugo
似乎有一个 bug
(这是ChatGPT
说的),如果要实现「相关文章」,分类名不能用中文,尽管我在config.yml
中开启了hasCJKLanguage: true
,依旧不行。相关文章是hugo-theme-ladder
主题中的一个功能,即在文章详情页最后会根据当前文章分类推荐10
篇同类型文章,也是为了增加 PV
嘛。
所以,我又改写了themes/hugo-theme-ladder-my/layouts/partials/posts/meta.html
实现了我的需求;原来的博客分类结构是categories: 读书看报
,有两个地方不满足:首先Hugo 的分类是数组结构,而且字段是series
,其次「相关文章」不支持中文。
调整方法如下:
- 在
config.yml
中将taxonomies
下series
的值改为categories
,这样历史的文章结构不需要调整 - 同时将文章中 categories 的结构改为「英文在前,中文在后」的数组结构,如
categories: ["Random Thoughts","胡说八道"]
即可,批量替换就像 themes/hugo-theme-ladder-my/layouts/partials/posts/meta.html
的代码如下:
<p>
<small>
{{ .Date | time.Format ":date_long" }} · {{ i18n "word_count" .WordCount -}} · {{ i18n "reading_time"
.ReadingTime -}}
</small>
{{ if .Site.Params.options.showMetaSeries -}}
<small>
{{ with .GetTerms "categories"}}
·
{{ end }}
{{ $categories := .GetTerms "categories" }}
{{ with index $categories 0 }}
{{ $href := .Permalink }}
{{ with index $categories 1 }}
<a href="{{ $href }}" target="_blank">{{ .LinkTitle }} </a>
{{ end }}
{{ end }}
</small>
{{ end }}
</p>
代码逻辑:取分类中第一个名作为「相关文章」的筛选条件和跳转
URL
,第二个作为显示名字。
新增图片备注信息居中
我的图片都是外链,格式如 ![v2.0 版本首页](https://dc-blog-img.demochen.com.cn/b17a1a52722f28d0d272da536d485f44.png!style:ToWebp)
,我希望其中类似「v2.0 版本首页」能在渲染后显示出来,处理方法如下:
- 在
/layouts/_default/_markup/
目录下,新建render-image.html
文件 - 该文件的代码如下:
<figure>
<img src="{{ .Destination | safeURL }}" alt="{{ .Text | plainify }}" {{ with .Title}}title="{{ . }}"{{ end }}>
<figcaption>{{ .Text | plainify }}</figcaption>
</figure>
调整 meta 元素中描述部分不显示问题
这部分是 SEO 需要的一些字段,在文章详情页是没问题的,我看了作者关于这块的源代码,其逻辑也是没有问题的,但是就是无法显示。最终发现是 description
字段在 config.yml
中位置有问题。将其挪到 params
下后,问题解决。
新增版权声明信息
原来博客有这个,新增是别人抓取数据的时候可以通过此信息补充文章地址。
添加方法:
- 在
hemes/hugo-theme-ladder-my/partials
目录下新增copyright.html
文件,代码如下:
<div class="copyright">
<style>
.copyright {
margin: 20px 0;
padding-left: 20px;
border-left: 5px solid #eee;
color: #666;
quotes: none;
}
.copyright:before {
content: open-quote;
}
.copyright:after {
content: close-quote;
}
</style>
<p>
作者:<a href="{{ .Site.Params.homepage }}">{{ .Site.Author.name }}</a><br />
链接:<a href="{{ .Permalink }}">{{ .Permalink }}</a><br />
声明:除非另有声明,本文采用 <a href="{{ $.Site.Params.licenseLink }}" target="_blank">{{ $.Site.Params.copyrightLicense }}</a> 协议,转载请注明。
</p>
</div>
- 在
config.yml
文件夹中,新增协议许可配置文件,代码如下:
params:
copyrightLicense: "CC BY-NC-SA 3.0"
licenseLink: "https://creativecommons.org/licenses/by-nc-sa/3.0/cn/"
- 在文章模版文件
themes/hugo-theme-ladder-my/layouts/posts/single.html
找到文章结尾的标签,新增第二行代码
<section class="blog-content">{{ .Content }}</section>
{{ partial "copyright.html" . }} //新增这一行代码
底部新增友情链接
我目前的友情链接用的是文章的形式,方便自己自由编辑,但是我自己也有一些其他的站,还是希望在底部增加一些友情链接,作为 SEO 导流的效果。添加方法如下:
config.yml
添加友情链接
# 友情地址
params:
links:
- name: "特立独行的异类"
url: "https://www.demochen.com"
- name: "今天长这样"
url: "https://today.demochen.com"
- name: "DemoChen's Clip"
url: "https://clip.demochen.com"
- name: "DocHub"
url: "https://www.dochub.wiki"
- 在
themes/hugo-theme-ladder-my/layouts/partials/footer.html
中新增代码
<footer class="footer">
<p>....... since 代码 </p>
<!--添加下方代码-->
<p>❤️ 其他站:
{{ $totalLinks := len $.Site.Params.links }}
{{ range $index, $link := $.Site.Params.links }}
<a href="{{ $link.url }}" target="_blank">{{ $link.name }}</a>{{ if lt $index (sub $totalLinks 1) }}、{{ end }}
{{ end }}
</p>
</footer>
- 根据路径
themes/hugo-theme-ladder-my/assets/scss/
新建_footer.scss
文件,重写主题关于这部分的样式,代码如下
.footer {
display: flex;
flex-direction: column; // 修改了这里
align-items: center;
justify-content: center;
height: 8rem;
width: 100%;
padding-bottom: 1rem;
font-size: 80%;
margin-top: auto;
}
.footer p {
margin: 0.1rem 0;
/* 上下间距为 0.5 rem,左右间距为 0 */
}
菜单栏新增 new 标签
若当月文章有更新,则顶部「文章」菜单显示 new
,提醒读者有更新。主要修改 themes/hugo-theme-ladder-my/layouts/partials/header.html
文件,代码如下:
<ul class="navigation-list" id="navigation-list"> <!--加在这个后面-->
<!-- 20230806 add icon news start-->
{{ $currentMonth := now.Format "2006-01" }}
{{ $hasNewArticle := false }}
{{ range where .Site.RegularPages "Section" "posts" }}
{{ if eq $currentMonth (dateFormat "2006-01" .Date) }}
{{ $hasNewArticle = true }}
{{ end }}
{{ end }}
<!-- 20230806 add icon news start-->
{{ with .Site.Menus.main}} <!--加在这个前面-->
<!--分隔符-->
<li class="navigation-item navigation-menu">
<a class="navigation-link" href="{{ index (apply (slice .URL) (.Params.urlFunc | default "relLangURL") ".") 0 }}">{{ .Name }} <!--加在这个后面-->
<!-- 20230806 add icon news -->
{{ if and $hasNewArticle (eq .Name "文章") }}
<span class="new-icon-desktop" style="color: red; font-size: 10px; position: absolute; top: -12px; right: -19px; display: none;">new</span>
<span class="new-icon-mobile" style="color: red; font-size: 10px; position: absolute; top: -10px; right: 103px; display: none;">new</span>
{{ end }}
<!-- 20230806 add icon news start--> <!--加在这个前面-->
</a>
</li>
<!--分隔符-->
<!-- 20230806 add icon news 加在最后 -->
<script>
function adjustNewIcon() {
var newIconDesktop = document.querySelector('.new-icon-desktop');
var newIconMobile = document.querySelector('.new-icon-mobile');
if (window.innerWidth <= 768) {
newIconDesktop.style.display = 'none';
newIconMobile.style.display = 'inline';
} else {
newIconDesktop.style.display = 'inline';
newIconMobile.style.display = 'none';
}
}
window.addEventListener('resize', adjustNewIcon);
window.addEventListener('load', adjustNewIcon);
</script>
<!-- 20230806 add icon news start-->
首页推荐阅读末尾引导到列表
考虑到首页只有推荐的文章,列表可能会被忽视,故添加了这个功能。需要修改 themes/hugo-theme-ladder-my/layouts/partials/home/profile.html
文件,代码如下:
<div class="featured">
{{ partial "home/featured.html" . }}
<!-- 20230806 more-content start -->
<div class="more-content" style="margin-top: 20px;border-top:1px dashed #6c757d">
<blockquote>
<p>📣 首页篇幅有限<br>🏃 更多内容请移步「<a href="{{ "archives/" | relURL }}">文章列表</a>」查看</p>
</blockquote>
</div>
<!-- 20230806 more-content start -->
</div>
其他的如添加统计、评论等功能,@GuangzhengLi 已经写的比较详细,根据文档查阅即可,基本上一步到位。最后把 sitemap.xml
等搜索引擎相关的文件都一一验证,然后部署上线了。
整体感受
看起做这些事情比较「花哨」,毕竟真的来看我博客的人很少,但是做这件,不仅能让自己身心愉悦,还能了解一些新的事物,何乐而不为呢?最后补一下博客所用的的产品,除了「域名」和「图床」是需要付费的,其余均免费。
作者:DemoChen
链接:https://demochen.com/posts/20230804/
声明:除非另有声明,本文均采用 CC BY-NC-ND 4.0
协议,转载请注明
赞助:若你觉得本文对你有启发,非常欢迎你成为我的 Sponsor ,感恩遇见