2026年我好了伤疤忘了痛再次使用static site generator建立个人博客的下场

how this all began? 怎么又来?

这一切的初衷是我想:

  1. 在博文里正常(以现代软件之姿)贴图(否则在时间物质——一个writefreely平台——已经完全够用了)。
  2. 有一个存储迄今为止比较有用文章的地方,最好是用markdown格式,而且发布到任何地方都能直接从这里复制——其实就是维护 a single source of truth。

从十年前也就是2016年开始,我就开始反复制作自己的网站,并在这个过程中终于入门了前端三件套。就在我渐入佳境时,llm闪亮登场,于是我又失去了大部分前端能力,变成了躺在llm怀里嗷嗷吃奶的小婴儿。此为题外话。

即使技术力下降了,经验却不会丢失太多。我很快锁定了一些建站方案,并颇为自信地认为有了llm和个人知识的加持,我将水来土掩轻松上手任何一个static site generator。但接下来的经历却表明,人类(至少是我)往往会忘记过去的创伤,又在第n次吃一堑长一智中痛苦地恢复记忆。

最初的方案们

hugo,不祥的开局

最终还是先尝试了hugo,所谓“先尝试”,就是打开hugo theme gallery,看看有没有自己喜欢的主题。

我喜欢的主题

炼狱之旅(只是炼狱,不是地狱)

最后我选择了tufte。选择的过程涉及一些玄学,回头想想,这么简单的事情为什么要用玄学呢?但或许正因为无足轻重,所以可以用宇宙的随机状态来决定吧。

我开始归档以前的github pages repo,并创建hugo站点。这个过程很简单。先用winget安装hugo本体,然后把tufte以submodule的形式链接到这个repo。echo "theme = 'tufte'" >> hugo.toml出了点小问题,不知为何echo写入的全是乱码,但手动打开写入正确内容后解决了。

当我键入hugo server的时候,一件悲伤的事情发生:

(此处省略很多行)...execute of template failed: template: _partials/header.html:15:3: executing "_partials/header.html" at <partial "header.includes.html" .>: error calling partial: maximum template call stack size exceeded in "<path to my blog>\\themes\\tufte\\layouts\\partials\\header.html"

好吧,循环引用。搜索了一下github issues发现要改成:

After replacing resources.ToCSS with css.Sass in header.includes.html, I was able to build with hugo v0.144.1, but still got the same error with the latest version!

这么修改之后就有新的错误了,真是好消息不断啊:

executing "_partials/footer.html" at <.PrevPage>:  
can't evaluate field PrevPage in type *hugolib.pageState

这个还比较容易修,只需要把所有 .PrevPage改成.Prev,把所有 .NextPage改成.Next就行了。

然后hugo server,一切顺利。

炼狱中的沉思:前端大爆炸及其他

这时我看着空空荡荡的localhost:1313,陷入了沉思,整个大脑浸入热水浴般的疲惫。倒不是因为修那几个bug多么费事——只有两个而已——而是这一切都让我仿佛回到了2018年,那时候只要有借口不做作业,我可以彻夜改写网站的模板文件,而且别忘了那是个没有llm的时代,陪伴我的只有一次次网页崩溃和搜索。

而且我想起,在那些前端大冒险中,我几乎没学到什么有用的前端知识,除了跟着时灵时不灵的网页教程操作、咬牙解决一期一会的bug、培养出卓绝的忍耐力之外。

因为那些代码并不是我写的。我得解决一大堆我并不理解、超出我知识范畴的问题。最后我并没有留下什么有用的记忆。

只有几年后,我开始用vanilla js和css构建非常简单的网页应用之时,才悟到前端的现状是层出不穷的叠床架屋。无数工具为“省事”而发明出来,但作为入门者,如果我从来没感受过“费事”,我永远不会知道我用那些package都省了什么事。

我也承认我并非一个那么爱尝试新事物、爱折腾的hacker。但也不止我一个人觉得前端世界一团乱麻。越深入这个领域,我越觉得这里有一种浮躁的性格在起作用。I feel people tend to show off a lot in the world of frontend, but that tendency actually helps the career, because frontend is about veneering.

回归正题。2018年的时候我还年轻,我还不是那么opinionated,还在跃跃欲试,并觉得世界上一切存在都有其道理。那时候我不会觉得.PrevPage.Prev的deprecation有什么问题,不假思索改了就行。但现在我只觉得这种修改背后可能隐藏着一百个糟糕的设计。

我疑心病犯了。

当然,我应该对它们更宽容一点。ssg并不是一个简单的系统,因为用户可能想用它建立各种网站——文档,博客,landing page,简历,等等。

我逐渐回想起ssg要包含的各种功能:嵌套模板,i18n,config(噢天哪,config!),pagination,category & tags,统计数据,评论区,插件……一大堆东西。我也同时头皮发麻地回想起我和这些功能打交道的痛苦过程。

总之,ssg得在通用性和易用性之间做出权衡。如果设计得过于通用,那编写config就会是一场苦旅。config和内容frontmatter会越来越复杂,直到模板比生成出的页面还长——哦,对了,最通用的ssg系统不就是手搓每一个html文件吗?

ssg的主题系统也已经不只是主题了,而是一套完整带样式的内容模板——如果你下载了一个用于简历的主题,那就很难把它改成博客。至少hugo是这样的。每个主题的内容模块和样式都打包在一起,每个可能都implement了自己的评论系统配置方式,一旦切换,就要重写配置……

我想起,正是因为受不了这些“多余之物”,才会在2021年左右回到vanilla网页——宁愿手写html,也不想再吃不受自己控制的代码之苦了。

hugo + obsidian?

一开始我是想用obsidian来配合hugo的,但最后没有实行。

Some links I've found but haven't read on this topic:

astro 和 retypeset theme,一段孽缘

obsidian-digital-garden,返璞归真

Digital Garden - Publish Obsidian Notes For Free

custom css

为什么默认首页title是notes?

修改路径导致文章重复

这时需要重新发布所有文章,而不是publish active note,才能删除错误的重复文章。

特别顽固的白色背景

最后以这样的方式修好了:

.theme-light {
  --background-primary: #f8f7f6;
  --background-secondary: #f3f2f1;
  --text-normal: #333;
  background: var(--background-primary);
  color: var(--text-normal);
}

260223-markdown-test is weirdly broken from time to time

analytics

根据这个issue操作,只需要:

  1. 打开vercel analytics(因为我把网站host在vercel上,它这个免费套餐可以看30天的数据)
  2. 在我的网站repo里新建src/site/_includes/components/user/common/footer/analytics.njk(github可以直接新建文件,键入/会创建新目录)
  3. 在里面粘贴:
     <script defer src="/_vercel/insights/script.js"></script>
     <script defer src="/_vercel/speed-insights/script.js"></script>
    

这样就完成了。

dataview列表的标题里不能包含|

否则好像|后面的内容都会被切除。