个人网站迁移到Haunt的心得

过年那时候想着,想着既然都过年了,那不如新年早点把个人网站和域名的迁移弄好,于是这么想着就开始做了,买了新的域名,然后开始迁移自己的个人网站到新的服务器上,换博客框架其实主要是想着既然都换服务器了,那顺便把博客的框架也换一下,隔壁South Fox用的那个Haunt也是我一直想用的静态网站生成器。

写在前面

过年那时候想着,想着既然都过年了,那不如新年早点把个人网站和域名的迁移弄好,于是这么想着就开始做了,买了新的域名,然后开始迁移自己的个人网站到新的服务器上,换博客框架其实主要是想着既然都换服务器了,那顺便把博客的框架也换一下,隔壁South Fox用的那个Haunt也是我一直想用的静态网站生成器。

没想到这么折腾不知不觉就过完年了,个人网站的基本功能刚好也折腾好了,把以前写的部分文章整理到了新的Blog,还顺带把Matrix服务器和电子邮箱服务器也迁移了一下。

新域名的规划

这一次,我是将个人博客和域名一起迁移的,迁移域名的主要原因,一方面是因为用旧的域名的时候不知道根域名可以通过well-known的手段让Matrix服务器也能像电子邮箱服务器那样用根域名代理,觉得旧的域名身份不太优雅,另一方面则是考虑到未来有建立自己的游戏工作室的需要,最好换个能代表个人工作室的正式点的域名。

本来是打算直接用工作室的英文拼写littlewing.studio做新的域名的,结果看了一圈发现,littlewing开头的不知道是不是因为意象太好,大部分价格都不是普通人能买得起的,我倾向于优先选择更为稳定且比较正式的com或studio域名,因此也可以过滤掉一些杂七杂八的小域名之类的。

所以最后我干脆原地造词,用kikowiwu替代littlewing的意思,kiko在我自创的人造语言香格里拉文中代表的是小孩子的意思,而wiwu代表的是翅膀的意思,所以kikowiwu的意思就是雏翼,初生的翅膀,和我想建设的梦想工作室的意象完全一致。

顺带一提,旧的域名兼本站的子域名yumieko,写法也就是作为本站banner的那个图标,yumi是自然和返璞归真的意思,eko代表的是我和日记的意思,词源是我这个代称,可以延伸出关于我的一切也就是日记的含义,这里的含义就是返璞归真的日记。

新的域名规划,我准备将根域名用于工作室对外展示的域名,主页也设置在工作室,将原本的一个秘密基地网站拆分成两个网站,yumieko和himiano,分别作为个人博客和个人作品集展示,之后再考虑单独弄个网站来展示个人企划的世界观之类的。

himiano这个词,himi代表的是情报、信息的意思,ano代表的是不可见的、隐藏的,也可以引申为藏身处的意思,结合起来就是情报隐藏之地,也就是秘密基地了。当然这个词在香格里拉文中,更多地是指代冷门的小众宝藏地点,不可告人的秘密其实还有别的专门的词指代,不过那就是另外一个话题了。

然后matrix和activity pub服务器,本体都挂载单独的子域名下,通过well-known转发的方式让你能用根域名直接作为你的网络身份,这样一来个人的matrix和fediverse帐号也会美观不少。

Hugo

以前用的旧静态网站框架就是Hugo,这个框架的好处是用起来挺方便的,有很多主题,而且emacs有专门的ox-hugo插件来将markdown格式导出为org-mode。

但是用久了我发现,这个静态网站生成器的可定制性比较差,虽然我平时也没啥特别的定制需求,但需要定制的情况往往要想尽办法弄懂一堆难懂的屎山代码,很难对其进行多少特别的改动和折腾。

加上目前的ox-hugo工作流也不如通过NNW直接将文件导出到网站目录优雅,所以最终决定弃用hugo。

Haunt

这是我的新选择,之前偶然看到South Fox 写的关于Haunt的介绍,发现诶,原来Guile也有自己的静态网站生成器。

正好我这段时间也在考虑逐步用Guile生态来取代Python作为我的主要脚本语言,最终我就用上了Haunt,也许切换到Haunt某种意义上也是命中注定的相遇吧。

使用Haunt的理由挺多的,Haunt本身的代码感觉非常优雅和简洁,了解了下文档之后更是感觉使用起来还是意外地简单且轻松的。

而且Haunt基于Guile的特性,修改起来非常容易,因此也可以很方便地无缝和自己的其它工作流系统对接,我这里是用的NNW。

Haunt简单来说,是用SXML,即S表达式表示的XML语法作为中间层,因为SXML很方便转成HTML,所以只需要你的文本阅读器能将文本转换成SXML,就能直接将这个源做成Haunt。

因此,理论上你可以自己定制自己的一套Org格式的转换逻辑,对于我这种想用Org写静态网站的来说是个福音。

博客折腾

基础框架

入门haunt也不是那么轻松一下子就入门的事,不过好在找到了文档和参考的代码,基本看了看,就熟悉了Haunt的写法,参考的South Fox的部落格源码

当然,我个人觉得SouthFox的代码有点不太优雅,所以我只取了建站必须的一部分,不太必要的部分都没有借鉴,这是我的源码

网站的HTML排版格式和CSS样式,SXML里面的部分,大部分都是用Claude写的,同时结合了自己的一些修改,感觉用AI写这种前端底层又臭又冗杂的代码还是很方便的。

主题设计

我的主题设计,背景部分参考的Natsumi这个网站,这是一位日本画师的个人网站,然后排版布局部分也有参考Southfox的博客

因为我希望我的网站能做出一种千禧年的复古味道,同时兼具日记一般的温馨感,所以有特意让AI在设计上模仿这种千禧年网站设计的味道,实际效果还挺不错,偏淡黄色的主题也很有日记的味道,当然这个主题的配色是我想出来的,我提出一个模糊的配色思路,AI帮忙决定具体的配色方案。

Org解析

这一块虽然也算麻烦,但相对来说也不是特别麻烦,Org的解析我用的是之前ForkGuile Orgfile写的解析库实现,虽然粗体、斜体、代码块、表格之类的都缺,写本文的时候暂时也没写好这类支持,但至少最基础的标题和有序列表这类都能正常使用。

为了方便显示图片,我还更改了这个Org解析库的链接解析逻辑,用正则表达式匹配Uri,匹配到后缀有任意web图片格式的情况就会将SXML输出为img而非a块,此外还优化了在没有描述的link情况下的显示,会解析为内容名字为链接本身的a块。

之后因为考虑到要兼容图床,因为看了South Fox写的IPFS的介绍,我发现图床的话放IPFS上其实是最方便的选择,所以后面还在本站的Org解析模块中添加了自动将ipfs://和ipfsimg://开头的链接内容和网关拼接转换为链接或图片的功能。

虽然现在兼容很多都还不完善,不过我个人是尽量希望之后补上对各个内联语法的支持,以及对引用、代码块和org表格的渲染支持的。

文本工作流

最后就是文本工作流了,这一边是NNW侧的工作。

这次网站的搭建,因为考虑到尽可能节省搭建所需花费的时间,所以我也尽可能避免动NNW的核心设计架构。原本我是打算给NNW加个文本解析的功能,不过转念一想,其实好像没那么必要,就算要实现卡片链接功能,其实也只需要实现一个卡片链接解析的功能就足够了,毕竟,处理纯文本,不关心格式和排版才是知识管理软件核心的职责。

还有一个图片类型卡片和图片链接的功能,本来我也是想得很复杂,想要在NNW实现,当然这个现在也是未来待实现的一个Feature。不过我仔细想了想,因为实现图片卡片本身要动存储层,也很费时间去处理存储逻辑的兼容,而我目前需要的其实只是一个兼容图片类型链接的功能,最终转向了使用IPFS做图床来在文章中插入图片的折中方案。

我从Hugo迁移到Haunt最核心的原因之一就是觉得目前写文的方式不太方便,因为我个人更倾向于所有文章都能随时在Emacs的一个页面打开写和快捷键迅速导出,不需要任何额外的复制粘贴组合、也不需要复杂的键位操作和命令行导出文章,只需要保存后执行一个快捷键或命令的步骤就能自动化构建和上传的全部流程。

这也是我换到Haunt的理由了,因为Haunt本身自带一个Rsync publisher,虽然我本来是想试试看Cloudflare Pages的,不过看了看Cloudflare的文档,感觉接口还是太复杂了,于是最终放弃了Cloudflare托管个人网站的方案,选择用Haunt自带的Rsync Publisher将个人网站部署到自己的VPS上,总的来说这套发布流程还是很方便的。

NNW侧为了方便文章的导出,我写了NNW Exporter,并添加到NNW CLI的配置文件里面。这是一个非核心功能,基于标签来查询所有拥有特定标签的文章,并将这些文章做某种处理后,批量导出到特定的Haunt目录。

因为我是用Org格式写的,所以我写的exporter是NNW Org Haunt Expoter,这个Expoter会在导出时根据标签和写文章的日期,自动给每篇文章的开头附加上Org格式的元数据。

我还写了一个简单的摘要生成的规则,这个规则可以在设置好的限定字数范围内,自动忽略主题行,将多个行拼接成简单的摘要。注意这个字数限定只是一个模糊的字数范围,我尽可能避免截断段落,因此最终字数取决于拼接后的段字数,但只要监测到字数超过100就会停止继续往下取新的行塞进摘要。

写好这个exporter后,我在nnw4e也写了响应的代码,允许你调用nnw export来导出卡片。然后将nnw exporter的配置写到了自己的nnw配置文件中。

#:exporters

(list (org-haunt-file-exporter "~/Creator/kikowiwuri/yumieko/posts" "#Blog" "#yumieko"))

最后,我在我的Emacs端写了个简单的方法,

(defun nnw-export-and-haunt-publish ()

(interactive)

(nnw-export)

(async-shell-command "~/Creator/kikowiwuri/buildsites.sh"))

这个方法会执行我写在buildsites.sh里面的那套构建脚本,脚本内容本身很简单,就是haunt buildhaunt publish这两个命令按顺序执行的流程。

最后,将这个方法绑定到一个快捷键上,就可以优雅地在emacs只使用简单的按键组合快速将我的文章发布到服务器上了。