时间倒回到两年前,当时的我刚刚结束实习返校:闲着没事又开始折腾起博客,那时博客才更换成 SPA 没多久,由于 Bug 太多,主题各地方的细节我也不是太满意,体验了一段时间满足了新鲜感之后,心里忽然升起了一种对折腾博客的倦怠感。于是我还是换回了原来的 Material 主题,这一用就用了两年。

直到前段时间,Github 提示博客仓库有好几个 CVE 的漏洞,作为一个强迫症,自然是想修复这些漏洞,然而我发现这些漏洞是博客使用的一些 Hexo 插件的依赖造成的,有些插件作者都不再维护了,于是我便想弃用掉这些插件,找寻新的代替品;可又转念一想,就算找到了代替品,这种情况也还是会发生——毕竟我不能指望每一个插件的作者都不弃坑。权衡利弊之后,我决定从根源处解决问题——如果没有 Hexo,自然也就不会有插件依赖的问题了,因此我弃用掉了从建站伊始就使用的 Hexo 框架,转而投向 Hugo 的怀抱。

Why Hugo?

Hugo 并不像 Hexo 提供各种插件用来增强或修改框架本身的功能,不过好在 Hugo 框架本身的功能已经足够的多了,我只需要在上面做一些修改即可——这也正好符合我的需求,根据我自己的想法定制、维护,也就解决了让我弃用 Hexo 最根本的问题。

其实早在两年多前我就有尝试过将博客换成 Hugo,只是当时逛遍了 Hugo 的主题,发现没一个能打的,原因也很简单:Hugo 是基于 Golang 的,主题创作者大多是后端;Hexo 则是基于 Node.js,主题创作者大多数是前端,而主题样式则完全考验的是前端能力,因此 Hugo 主题的整体水平自然落后于 Hexo。

如今,既然我已决定使用 Hugo,那么不妨自己写一个主题。

主题的设计

本次主题我选择使用 Tailwind 作为 CSS 框架,它与其他 CSS 框架的区别在于默认不提供各种元素的样式,而是将各种 CSS 的属性预先定义成 class 的形式,这样如果我想控制某个元素的样式的话,只需要将对应的 class 名称加入元素的 classList 就好,颇有点声明式编程的意思。同时,由于 Hugo 集成了 PostCSS 框架,几乎可以让 Tailwind 开箱即用了。

在 JavaScript 方面,由于之前 Hexo 年久失修的插件给我留下的阴影,一开始让我使用它时我是拒绝的,可转念一想有些 JavaScript 的功能的确可以提升博客的体验(Lazyload,Workbox 等),于是开始秉持着「主体功能上不能依赖于 JavaScript」的原则来使用 JavaScript;由于 Hugo 已然内置了模块用于 CSS 的预处理和 HTML 的压缩工作,在发布时我只需要打包 JavaScript 就好,因此在模块打包工具上我选择了 Rollup.js——一个非常轻量的工具,只支持 JavaScript 文件的打包。

博客的一些改进

评论的加载

一般来说,博客评论的加载有以下几种方式(以 Disqus 为例):

  1. 最原始的方式:在用户进入文章页面直接加载 Disqus,但这会给页面带来非常多的额外请求从而拖慢加载速度,而且因为中国的局域网环境,会更显著地降低用户体验;
  2. 优化后的方式:默认不加载 Disqus 的评论,用户需要看评论时,点击按钮以加载评论,这种方式比上一种好很多,但也会给用户带来一次额外的点击操作;
  3. 将二者结合:用户进入文章页面时,先请求一个 Disqus 的配置文件,如果在给定时间内未超时,则自动加载评论;反之则需要用户手动点击按钮以加载评论,这也是我之前一直使用的方法,可这种方法仍然会拖慢页面的加载速度——如果给定的超时时间比较长的话,仍然会产生和第一种方式类似的问题;

博客的实践是在第三种方式的基础上做了一点优化:当用户进入文章页面时,不请求配置文件,只有当页面滚动到文章底部的时候才发送请求配置文件来测试 Disqus 的连通性,这样当用户首次进入文章页面时,页面的加载速度不会有什么影响。

文章的加密

博客是否需要加密文章,以及需要加密文章的原因不在本文的讨论范围。本文仅讨论实现手法

之前 Hexo 博客的加密是通过插件完成的,如今更换成 Hugo 之后,自然要自己造轮子了。其实加密博客的思路很简单,在编译成 HTML 的时候将文章原本内容使用 AES(或者其他的什么算法都行)加密后替换掉,在前端展示时,再让用户输入密码通过 JavaScript 解密就好。

这里我踩了两个坑:

  1. Go 的加密库与 JavaScript 的解密库的兼容性问题,Padding 函数需要设置成同样的,以及当密钥长度不够时的填充规则也要一样;
  2. Hugo 的 shortcode 不支持 Shell 命令的调用,因此我不得不采取一种非常别扭的方式:Hugo 生成 HTML 文件后,手动调用加密程序将指定的 HTML 文件中的内容替换再写入源 HTML 文件。

也由于第二个坑的存在,在本地使用 Hugo Server 调试时是没办法测试加密功能的,不过好在每次博客部署都是通过 Github Actions,配置文件写好之后倒也没有特别麻烦,只是心里总是觉得有根刺儿一样不舒服。


除此之外还有一些小改进,比如:

  • 所有的动画都是使用 CSS 实现的,不依赖于 JavaScript;

  • 所有的 JavaScript 都是延迟加载的,等到页面所有资源加载完成才触发执行;

  • 所有图片都是 Lazyload 的,考虑到 RSS 订阅的用户,文章内部的插图没有使用 Lazyload;

  • ……

主题的使用

一开始设计博客主题的时候,并没有打算发布,只想自娱自乐,因此将许多个人偏好耦合进了样式中,我也不打算改了,直接把博客开源吧。

博客的一些个人配置文件我使用了 Hardcode 的方式嵌入(比如 Google Analytics 的 ID),请注意修改后使用。

还有,因为包含加密的文章,所以我将 content 文件夹注册成了一个 Hugo Module(这个 Module 其他人没有访问权限),如果你想直接运行,最简单的方法是删除在配置文件和 go.mod 里的 Module 相关内容,然后将你的 content 文件夹拷贝到根目录,就可以运行了。

后记

促使我从 Hexo 迁移至 Hugo 的原因或许大多数人的眼里看起来甚至有点扯淡,但我当时的确已经无法忍受了。后来冷静下来想了一想,Hexo 本身并没什么不好的,反而其衍生出来的生态、主题美观度、模板语言、API 自由度比 Hugo 强了不止一点。

而我终究还是换成了 Hugo,究其原因应该是我已经对 JavaScript 的编译、打包、构建等前端工具链累觉不爱了吧——咦,那么我为啥迁移到 Hugo 之后还要使用 Rollup.js 打包工具呢,人呐,果然是矛盾的动物。

Last Updated in Sun Nov 15, 2020
This article under the CC BY-NC-ND 4.0. learn more
© 2017 - 2020 Wincer's Blog
Theme Cirrus designed by Wincer, built with Hugo