构建系统更新
作为上篇(实则上上篇)末尾提到的博客振兴计划的起点,花了几天时间将静态站构建从Jekyll切换成了手工编写的可执行程序。
一般来说我会抓住每次用Rust写(对我来说的)新鲜玩意的机会往知乎水点东西。这次放弃了这个念头,因为如果要写就要链接到这个网站作为成果展示,而显然这个站内的内容羞耻度并不适合面向公众展示。一个折中的方案是把抽取一个内容删干净了的模板仓库然后代为用以展示,但是我懒得搞。
技术性内容只写给自己看让人稍微有点不爽,但是一来就算写在知乎其实也没什么人看,二来就算只有自己会看其实也挺有意义的。比如说,如果不是因为有这个网站记录,我怎么也不会相信自己直到两年前的现在还在和C++较劲。总觉得已经写Rust写了好几辈子了。
犹记得当年创建这个网站时的思路。(不记得也没关系,反正写在了头一篇文章里。)总结起来就是突出一个能用就行。这个策略是很正确的,如果当时没有这般果断地完成搭建,我就没办法每当有感觉了就能在三秒钟之内进入可供写作的环境,从而留下如此一大堆除了总字数以外毫无可取之处的内容。
也正是在用了Jekyll和它的主题这般长的时间以后,我对它的不满足也逐渐清晰了起来。随便列举一些例子:
- 摘要不能保留markdown格式。
- 文章的文件名必须是
year-month-day-title.md
的格式。非要包含日期还可以接受,大不了写两行脚本生成一下,但是标题也出现在文件名当中就有违我的风格了。我的风格是文件名只使用ASCII字符,所以总是要起一个占位的标题,然后再在前言元数据里覆盖。然而搞了如此一通以后,构建系统并没有从这个文件名中提取任何信息,只是把它当作一个唯一标识符来用,让人不爽。 - 而且我又常常习惯于写没有标题的文章。
- 我还是受不了了,把后来的文章都写在了草稿文件夹里,省下了文件名当中的日期,但是也导致项目结构变得很怪。
- 虽然我嘴上说着能用就行,但是还是把使用的Tale主题自己fork了一份做些小修小补。上游不但已经断更了,最近甚至已经归档了。还想用的话就要自己去维护一个跟Ruby打交道的代码库,对于没(怎么)写过Ruby的我来说并不理想。
我想写静态网站生成器已经很久了。从本科时就开始在一遍一遍重新创建GitHub账号→创建博客→重新燃起实现一个博客生成器的念头。终于也是在这次填完了这个坑。近几年来还断断续续地写完了2048和简单的光线追踪渲染器,感觉本科想写的东西好像都写得差不多了。终于过上没有欠债的人生了么。
另外,写完这个构建系统以后,我意识到自己再也不用在网页端VSCode里写博客了。毕竟一开始在网页端写就是因为不想在本地配Jekyll环境,而现在就没这个问题了,反正我无论如何也要配Rust环境。
写掉这个项目的过程还是很直截了当的,大部分的时间都花在了研究第三方库的文档上。
解析markdown内容使用了markdown
库。看起来pulldown-cmark
要更先进一些,但是它的优势对我来说挺边际的。一个意料之外的情况是关于处理前言元数据,似乎没有库能在解析的结果中包含这些元数据,最好也只是支持解析时跳过它。所以我把它手动截取出来然后用serde-yaml
过了一遍。
解析scss样式用了rsass
库。
时间和日期的处理用了chrono
库。我决定不满足于读取包含时区的时间然后统一化的做法,而是把时区信息一直保留在元数据中,这样一来某种程度上写一篇文章的时间当中也包含了我是在哪里写的它的信息。另外这也可以避免把时间都翻译成新加坡时区以后对于自己写文章时的作息产生误解。
渲染html使用了maud
库。目前页面主题被硬编码在了lib.rs
里,因为它一共也就三百多行。以后可能会考虑把它拆成单独的文件乃至单独的库和样式集中管理之类的。
在文件结构上采用了类似Jekyll的方式,但是引入了基于文件层级的category结构。在同一个category下,文件名作为文章的主键,决定文章的默认展示顺序。绝大多数的(目前全部的)文章都是属于“默认”分类的,这个分类下的主键直接用时间戳,这也就是文章路径的各组成部分的含义。
调整了文件结构以后,我还收集了先前文章的路径迁移信息,以后有空做个html软重定向。没什么用,就是玩。
另外,离开了第一方的Jekyll支持以后,我自己添加了部署相关的GitHub动作。经过简单的了解,现在GitHub似乎支持上传自定义artifact并把它部署为GitHub Pages的工作流,但是我还是用了传统的自动提交构建结果到gh-pages
分支的动作,省去了配置动作权限之类的麻烦事。说实话,新的工作流确实没有足够的吸引力。
不过让我以外的是GitHub动作的默认镜像中现在已经预装了Rust工具链,居然有如此般的重视。另外actions-rs
组织也在最近归档了,不知道两者有什么关联没有。
整个实现过程中碰到的困难基本上只有一个:操作既有的html内容。
原本没有想到还有这种需求。实际上在两个地方碰到了:
- 提取摘要。因为我要做有markdown格式的摘要,所以就要先解析成html然后再提取。实际上,提取的逻辑还不是很显然:如果在顶层元素中找到了一个形如
<!-- more -->
的注释,那么就保留它之前的所有内容;否则提取第一个顶层元素。这使得提取不能基于简单的CSS选择来实现。 - 调整markdown的解析结果。目前的调整是对代码块的,需要将解析出的
<pre>...</pre>
调整为<div class="highlight"><pre class="highlight>...</pre></div>
。
调查了几个库以后,最后采用了用html5ever
库做解析和系列化,搭配markup5ever_rcdom
作为解析出的数据结构进行操作的方案。这些库,包括Rust生态中的其他html解析库,用起来都过于低级了,有浓重的内部使用,不面向终端用户的感觉。它们的接口设计很面向极致性能而牺牲易用性,并且它们常常对标准(甚至可能包含xml标准)提供一视同仁的完整实现,导致就算我只用最常见的元素和功能也被迫要了解到标准的方方面面。这大概算是一个生态缺位,但是对它的需求有多少我就不得而知了。
总之,这一块的代码写得最为凌乱,最后它能正确地跑起来也让我长出一口气。
写这个掌握在自己手里的生成器,除了解决上面那些长久的不满、完成一个夙愿以外,也是为接下来更灵活地自定义这个网站,从而真正全面振兴之做准备。随便列几个后续工作:
- 将markdown替换成根据我的习惯自定义的格式。比如说我非常想要直角引号,然而除非配置输入法否则很难打出来。比如说一些好用的latex格式,等等。
- 重新设计首页。大致思路是最新的一篇文章的条目+一些统计信息,比如全站共多少篇文章,多少个字符,全部读完要花多久,等等。
- 实装分类系统,替换掉目前当摆设的右上角导航。
- 加入标签系统。我一直设想的全自动标签系统是全站或特定分类共享一个标签池,然后对每篇文章进行检索,自动为之打上文内出现过的标签。这样如果想要添加额外的标签同样可以直接写在注释里取消渲染,属于是传统标签的一个拓展。
不过,目前最希望的还是昨天买的迷迭香能好好活下去。