为什么换 Hugo 了

1 月底又开始折腾,换成 Hugo 来构建博客了,原因是觉得之前用的 astro build 不够快,本地也慢。 以前给前司搞公司博客的时候,用 Hugo 处理起来速度飞快,体验极好。 就也想给自己的博客换成 Hugo 了。

其实上次打算改掉 Jekyll 的时候,就想着了换 Hugo 了,也不记得中途怎么被 astro 吸引跑去先试用了几个月的 astro。

astro 的好处是完全是 JS/TS 的天下,虽然稍微有点变体,但也是 React 或者 Vue 组件的思维,很好上手, 对于本就熟悉的前端开发人员来说,什么组件都能做很灵活,有种无所不能的错觉(。)

Hugo 的 templating syntax 就明显复杂很多,需要反复看文档。它和以前 Jekyll 使用的 Liquid 模板语法也有差别。

但个人体感重前端 JS/TS 的静态生成工具的通病感觉就是构建速度还是不够快,即使 astro 已经是用很快的 esbuild 来构建了,在之前的 github actions 里依旧要构建 210s。 最早给前司做博客的时候用的是 Hexo,单纯依赖 Nodejs,更加是坑爹货。随着图片资源的增多,build time 也不断增加,居高不下。

换成 Hugo 后,即使是每次都是从头构建,也最多只需要 100s。其实我本地已经有处理过的静态资源了之后,每次构建都只需要 1-2s。

虽然一定要说的话,我也很不喜欢 Hugo template 的设计,写起来挺难受的,要不停查文档,还不方便 debug。 让我一个前端写的话,当然是直接手搓各种组件最舒爽。

但一切都是 tradeoff。

换成 Hugo 我本地搞起来很幸福。参考一些博客,也加了一些小功能。

【放弃惹】嘟嘟 shortcode

本来想加个 shortcode 用来显示长毛象嘟嘟,代码如下:

{{ .Page.Scratch.Set "include_mastodon" true }}
{{ $server := .Get "server" | default "m.cmx.im" }}
{{ $user := .Get "user" | default "zhuzi" }}
{{ $width := .Get "width" | default "100%" }}
{{ $height := .Get "height" | default "auto"}}
{{ $dodo := .Get "dodo" | default "false" }}

{{ if eq ($dodo) "false" }}
{{ else }}
<iframe src= "https://{{ $server }}/@{{ $user }}/{{ $dodo }}/embed" class="mastodon-embed" style="max-width: 100%; border: 0" width="{{ $width }}" height="{{ $height }}" allowfullscreen="allowfullscreen" allow=""></iframe><script src="https://{{ $server }}/embed.js" async="async"></script>
{{ end }}

但是显示不出来,console 里有报错显示长毛象不能跨域显示在 iframe 里,所以放弃了。

Refused to display ‘https://m.cmx.im/' in a frame because it set ‘X-Frame-Options’ to ‘sameorigin’.

NeoDB 卡片

8.3
早已过了而立之年的一子(安藤樱 饰)整天百无聊赖,她根本无心帮助打理自家的料理店,整日玩游戏虐杀小外甥。她的妹妹二三子(早织 饰)离婚后回到娘家,极度看不惯姐姐的作为,为此两姐妹甚至大打出手。自感不被家人所容的一子搬了出去,并在日常光顾的百元超市谋得收银员的职位。这间小店云集着许多怪人,患有忧郁症的店长、话唠猥琐的同事、因盗窃被开除却还时常回来拿临过期食品的老太。在这些人中间,一子的心情愈加苦闷。偶然机缘,她和名不见经传的拳击手狩野(新井浩文 饰)走到一起,无奈他们之间甚至连爱情都谈不上。极度压抑之际一子选择学习拳击,她渴望释放心中不委屈和不满,渴望获得哪怕只有一次的认可。 本片荣获2014年日本电影旬报十佳影片第八名。
movie

参考这篇教程。 但我把右上角和星星的颜色都改成了粉色。

星星是直接用 svg 当作背景的,并且是直接 base64 的嵌入。

.rating .allstarlight{
  position: absolute;
  left: 0;
  color: #f9a8d4;
  height:16px;
  overflow: hidden;
  background-size: auto 100%;
  background-repeat: repeat;
  background-image: url(data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMzIiIGhlaWdodD0iMzIiPjxwYXRoIGQ9Ik05MDguMSAzNTMuMWwtMjUzLjktMzYuOUw1NDAuNyA4Ni4xYy0zLjEtNi4zLTguMi0xMS40LTE0LjUtMTQuNS0xNS44LTcuOC0zNS0xLjMtNDIuOSAxNC41TDM2OS44IDMxNi4ybC0yNTMuOSAzNi45Yy03IDEtMTMuNCA0LjMtMTguMyA5LjMtMTIuMyAxMi43LTEyLjEgMzIuOS42IDQ1LjNsMTgzLjcgMTc5LjEtNDMuNCAyNTIuOWMtMS4yIDYuOS0uMSAxNC4xIDMuMiAyMC4zIDguMiAxNS42IDI3LjYgMjEuNyA0My4yIDEzLjRMNTEyIDc1NGwyMjcuMSAxMTkuNGM2LjIgMy4zIDEzLjQgNC40IDIwLjMgMy4yIDE3LjQtMyAyOS4xLTE5LjUgMjYuMS0zNi45bC00My40LTI1Mi45IDE4My43LTE3OS4xYzUtNC45IDguMy0xMS4zIDkuMy0xOC4zIDIuNy0xNy41LTkuNS0zMy43LTI3LTM2LjN6IiBmaWxsPSIjZjlhOGQ0Ii8+PC9zdmc+);
}

base64 decode 其实很简单。打开 console,直接使用 atob() 函数就可以解码。 这个是浏览器自带的全局函数,详见 MDN 文档

解码出来的就是一个 SVG 图片了,它就是星星的原图。博主给的教程里星星的颜色是固定的橙色,是因为在最后 path 元素上设置了 fill="#f99b01" 也就是 SVG 的图上的线的颜色。

手动把它改成自己想要的颜色就是一个新的 SVG 图片了。 然后再把它 base64 encode 重新填回原来的 css 里即可。

decode 函数是 atob(),encode 函数也应该很好猜了,就是 btoa(),详细参考 MDN 文档

delay display 动画

早先是打开一位大神的博客 paco.me,首页有个很简约的延迟逐步显示的动画我很喜欢。 仔细看了下实现,其实也很简单。 具体来说,就是先设置一个简单的 fade-enter 动画:

@keyframes enter {
    0% {
        opacity: 0;
        transform: translateY(10px)
    }

    to {
        opacity: 1;
        transform: none
    }
}

效果也就是从下往上进入,并逐渐显现。

然后设置了一个 attribute selector 的基础设定。

[data-animate-enter] {
    --stagger: 0;
    --delay: 120ms;
    --start: 0ms
}

@media (prefers-reduced-motion:no-preference) {
    [data-animate-enter] {
        animation: enter .6s both;
        animation-delay: calc(var(--stagger) * var(--delay) + var(--start))
    }
}

然后给想要添加动画的元素上直接加上 data-animate-enter attribute 即可,比如:

<header class="page-header" data-animate-enter>
...
</header>

不过只添加这个 attribute 只会让所有添加的元素一起进入,不会有逐步进入的效果。 想要实现逐步的效果,只需要给不同的元素依次设置 stagger 值即可。比如:

<header class="page-header" data-animate-enter>
最先想要显示的,当作第 0 步
</header>

<p data-animate-enter style="--stagger: 1;">想要显示的第 1 步</p>
<p data-animate-enter style="--stagger: 2;">想要显示的第 2 步</p>
<p data-animate-enter style="--stagger: 3;">想要显示的第 3 步</p>

这样 animation-delay 就会根据不同的 stagger 计算不一样的延迟时间,整体上看就会有逐步显现的效果了。

恢复评论功能

以前一直是用 Disqus 当作评论系统,但早先听说 Disqus 好像把所有研发都裁了,所以总觉得不太保险了。 就一直想着换成别的,经过一番研究,本来想完全换成 twikoo 的。

但配置好了之后,本来想把 Disqus 的评论(这几年下来累积了 280 多条,虽然有一半应该是我自己的回复🤣) 全部 import 到 twikoo 的。

首先第一步是从 Disqus 导出,那段时间我怎么也收不到导出的邮件,也完全找不到 Support 可以求助, 毕竟我也就是一个普通 free 用户,没付钱。就真的在想 Disqus 是不是要完全倒闭了。

虽然过去的评论就算全都丢失了也没太大关系,但本意还是希望能保留就保留。 在推上吐槽了之后,有推友说他导出没问题啊,于是我过了几天又尝试了一次,才终于导出来了。

导出的下一步是在 twikoo 上 import,这里怀疑是哪里有 bug。

因为我在改框架的时候改过文章路径,而 Disqus 又是以路径作为 identifier 的。 所以当时在改框架时进行过 migrate,就是把旧的路径和新的路径进行一个一一映射。 但是这个映射关系在导出的数据里是缺失的。

我没有注意到这个事直接 import 了,然而现有的路径和旧的路径就对不上了,旧的 disqus 的评论其实都显示不出来。 失去了映射关系也是我到这一步才发现的。

我本来想手动修改数据文件里的数据,然后再导入,但是经过了一些手动更改,再 import 就直接报错格式不正确。 具体是哪里不正确实在很难找出来,于是我就放弃导入这个操作了。

因为轻微的强迫症,还跑去 MongoDB(Twikoo 用的数据库) 的 web 后台手动删除了前面一次 import 的不正确路径的 200 多条评论。 (悲催的是它这个 web 后台没有批量操作的功能,我是最笨最傻的点击了可能 500 次一条一条删除了,删除一条还要确认一次,所以每删除一条要点 2 次😂)

现在换成 Hugo 后,我参考鱼老师的博客改成支持 3 种评论系统,最古早的 Disqus、 利用 GitHub Discussions 而不是 issue 的 Giscus(这个配置起来是真的简单方便) 以及 Twikoo,主打一个任君选择。


一直以来博客的构建都是 GitHub Pages,但最早的 Jekyll 是它原生支持的,Build time 就不短。 后来换的 Astro 和 Hugo,都是借用 GitHub Actions 来构建的,时间依然很长。

最近有象友推荐用 Cloudflare Pages,速度吊打 GitHub。 等我研究清楚怎么用,可能就会从 GitHub Pages 换成 Cloudflare Pages。

其他的功能可能还会添加。Let me see see。