MADL!AR
Code is cheap, show me the PPT!

重构写作工具-流年笺

分类: ssg 发布于: 2026-08-17

偶然的重构动机

这个博客最早于2014年上线,当时使用 Jekyll 作为 SSG,托管在 GitHub Pages 上。受限于当时的技术水平和学习能力,我觉得 Liquid 语法十分别扭。更麻烦的是,每次调试都需要 push 到 GitHub,等待几分钟后不断刷新页面才能看到效果,体验极差。那时也没想到可以在本地部署实时预览,所以没用多久就弃用了。

后来写过一个单页面的博客,我把所有文章都嵌入到一个 JS 文件中,通过git action自动触发构建,就是这个版本:https://madliar.com/original-intention。现在回想起来,这大概是我做过的最愚蠢的决定之一——所有文章打包进单个文件,每次访问都要加载全量内容,首屏加载十分缓慢。而且所有页面都只有一个URL,单个页面无法通过链接直接分享或定位,完全丧失了SSG的独立、静态优势。可以说,看似“极简”,实际上同时牺牲了性能、可维护性和阅读体验。于是我又回归了 SSG 方案,并顺手写了一个预览器——这就是第一版 Markdown 编辑器:

我给他加上了历史记录、目录层级和分享功能,拿来写文档、给客户看草稿,界面虽然糙了点,用着倒还顺手。后来在没做任何安全防护的情况下,开放了注册,就此埋下了安全隐患。某天突然收到云厂商的告警短信,说实例异常,于是我尝试用SSH连接实例进行维护,但已被彻底卡死,最终使用旧镜像进行了回滚。但几乎可以确定,就是这个编辑器出现了问题,可能遭遇了恶意注册机的攻击。

我使用 AI 来分析这个工程的代码,竟一口气列出十几项漏洞:用 email 当用户隔离路径,容易被注入攻击;目录操作没有 dry-run 和输入清洗,一个 ../.. 就能逃逸到其他用户空间;页面和各种读写接口更是灾难,没做 escape,几乎处处都是注入点,跨域攻击也防不住……这些在之前似乎从未被考虑到。于是让 AI 模拟攻击,尽可能尝试不同方式、推演最坏结果,果然,它能轻易获取甚至删除任何文件。

这次经历让我想对这个编辑器进行一些完善。但它毕竟是多年前的产物,用的是老旧的 Bootstrap 和 jQuery,很多代码连我自己都已很难看懂。考虑到如今 AI 的能力已十分强大,我打算使用 AI 进行辅助。我问,改成现代化 UI 并做好安全加固需要多久,AI信誓旦旦列出一系列表格,表示两天足矣。于是我按照建议,用现代的tailwindCSS控制页面,使用更轻量的 Alpine.JS 作为前端框架进行重写。可谁知,这一重构就拖了个把月,几乎占掉了全部业余时间。最终成品长这样:

历史记录的功能设计

其实整个项目并没有什么什么高深的技术,更多的是方案的萃取和取舍。在使用 AI 重构的过程中,我也深刻的体验到各方的限制,不管是 AI 还是 Alpine.JS,都有明显的能力边界。为了防止重蹈覆辙,在这里记录一下最容易遗忘的部分,也就是历史记录的功能模块。

<技术细节略>

命名为《流年笺》

写这个工具前后花费了一个月,在最后一行说明文档的句号落下时,恰好已是深夜。当时我独自坐在保定出租屋的窗前,外面突然狂风大作、电闪雷鸣,不一会就下起了大雨。这种情境下,不由得想起一首诗:

夜半听风雨,挑灯书流年。 此中有真意,忘言亦忘眠。

这首诗的意思是,原作者经常在夜晚伴着风雨声书写笔记、感悟,记录过往经历和见解。因为沉浸在"真正的意味"当中,常常忘记要说什么,也忘记了睡眠。

我感觉到,这首充满蝉意的诗似乎就是整个项目最合适的注脚。"流年"通常指代流逝的年华、时光。在中文里,它用来形容时间流逝,带有一种诗意、怀旧、记录时光的意味。而"笺"——信笺、便笺、精美的纸张,用于书写。编辑器是"落笔"的地方,"流年笺"暗示这个工具是为安静书写、记录时光而生,恰好对应这种时间维度的内容积累。于是我将其命名为:《流年笺》。

ROI的考量

原本只打算用两天时间写完这个工具的,谁知搞了一个多月,并且坦率讲这一个月投入到编辑器上的ROI极低。SSG(Static Site Generation)这个行业其实已经“卷到头了”,Next.js, Astro, Hugo, VitePress 等工具能覆盖99%的应用场景,所以一开始决定重写这个工具就是不理智的。

由于选型上的失误,没有办法复用同一套渲染管线,导致前端使用marked.js、后端用mistune,80% 的精力都是在与边界条件做斗争。本来就是一个自用的工具却进行了大量过度的设计,做了很多通用性性功能,这也使得在开发过程中耗费了大量精力处理边界条件、做无尽的测试。像 Markdown 解析的边缘 case、路径拼接的 bug、renderrer兼容性……这些事从功利的角度上讲没有任何价值。

我把感受提交给 AI,请他分析这个过程中的得失和建议,有这么几条:

写博客的意义

打磨这个工具是为了更方便的写博客,但是从ROI的方面,我也重新思考写博客的意义。这个站点的域名“madliar”注册于本科时代,一方面是致敬乔布斯说过的「那些疯狂到以为自己能改变世界的人,才能真正改变世界」,另一方面取自硅谷[fake it till you make it]的老梗,拼凑了这个“疯狂的(mad)骗子(liar)”。当年取这个名字时候,是觉得“偏执=酷”,意图贴个醒目的技术人标签来表达自嘲式浪漫。这种感觉就像,青春期的少年穿着非主流的牛仔裤,屁股上印着“I'am a hacker”来显得自己很酷,展现自己的独一无二。这种直白的感觉在现在看来,其实是有点尴尬的。

从上线之日起,这个博客已经经历12年了,然而客观的来讲,这个站点并没有什么有价值的文章,即使论数量,也可以用贫瘠来形容。但在这十几年间,并非没有发生过有价值的事情,相反,有太多值得被记录和记住的,没有来得及被写下就已经被忘却了。于是在整理编辑器的这段时间,我决定重新开始运营这个站点,让它更精炼一些。

我想从换域名开始,翻了好几页短域名列表,要么被注册了,要么没有实际含义,取名这件事还是太困难了。纠结了良久才想通:其实也没什么不好的,不过就是年少轻狂时“以为能改变世界”证据罢了,即使不够完美,也见证了走过的十几年的路,这个带着bug的旧标记仍然有存在的意义。

老实说,过去十二年没写下来东西,不是因为域名不够好,而是因为一直把"写"当成了一种表演——好像每篇文章都得是篇技术干货,每篇都得有人点赞,每篇都得证明"我没在混日子"。但那些真正值得记住的事,从来不是写给别人看的。这些事没有ROI,不会出现在简历上,但它们构成了真实的、活过的证据。所以这个博客系统,它首先应该作为一个给自己的收件箱——写给未来的自己,写给那些正在被遗忘的流年。至于有没有人读,其实是次要,重要的是,别再忘了。