最近在给我们自己的英文技术站点 Mona 增加搜索功能时,经历了一次从弃用到重新拥抱 Pagefind 的过程,感触颇深,故而撰文分享一下。
故事的背景:
- 我们的站点虽然 Astro 为主体,但采用了 vercel serverless adapter。不会在 build 时按传统方式生成静态文件,至于原因,懒得说了。
- 如我以前的文章所言,目前的开发过程中已经重度采用 Vibe Coding,并不限定具体工具,但我主要用 Claude Code。而且,这个站点也主要是我来开发,团队其他成员则偶尔帮忙一些前端样式或者跟 ops 有关的优化工作。因为他们有更重要的事情要做,😄。
- 在主要支持的内容类型(文章、知识卡片、Slides )完成后,我开始考虑搜索功能。
于是乎,故事开始了。
Astro 生态下搜索相关的主要技术选项
Pagefind
当下,Astro 站点的搜索大多采用 Pagefind 来作为搜索引擎,并且还有专门的 Astro 插件 来简化集成工作。我在零成本打造自动化笔记发布流水线中提到的的笔记站点,也采用的是 Astro + Pagefind 组合。
它的主要特点:
- 易用、速度快并且提供了缺省的 api 和 ui。结合
astro-pagefind
插件,集成非常简单。 - 支持多语言
- 需要先构建索引。
此外,它的更新很频繁。
Fuse.js
Fuse.js 则是另一个轻量级的模糊搜索库,使用简单且灵活,支持离线和在线索引。但是 ui 和 api 都需要自己实现。
更新频率不如 Pagefind。
其他
对于搜索这类永恒不变的需求,当然不会就这两种,随手让 Gemini 做个 Deep Research 就能找到更多选项。但结合到 Astro,并不算特别突出,因此就不赘述了。
第一次选型:Claude Code 选择了 Pagefind
因为技术网站算不上太复杂的应用,并且搜索这类也算时常规需求,自诩 Claude Code 车技娴熟的我也就没有多想就把需求交给了它。Claude Code 自行调研完一圈之后说:astro 圈内主要就是 Pagefind 和 Fuse.js,由于一些原因(此处省略若干字),我打算用 Pagefind 来实现。
讨论一圈之后,我觉得没问题,就放手让它干了。很顺利,不到半个小时,它就向我报告说完工了。我兴冲冲一测,大失所望,完全不符合预期。
在让它自行调研一圈未果之后,我决定自己看看,此时我才注意到命令行上有输出说:Pagefind 发现 0 个页面。
这时我才想起来,咱们的站点不太传统,不会在编译时构建静态 html 文件,尴尬了!
第二次选型:在我的主导下,Claude Code 选择了 Fuse.js
在 rollback 之后,我重新略作思考,便将问题现状跟 Claude Code 说了一下,同时强调让它自己调研 Pagefind,结合我目前不能生成静态文件的现状,看看有没有解决方案。
为何不直接告诉它呢?主要两点原因:
- 省事
- 它自行思考之后,能更好的计划,生成好结果的概率更大。
在自行调研和我的引导之后,它得出结论:Fuse.js
,理由如下:
- 当前的内容类型跟传统技术站点不太一样,因为有 knowledge card 和 slides 这两个强交互的内容类型,不适合静态生成。
- Pagefind 需要事先根据静态文件生成索引,因此不适合当前的站点。
- Fuse.js 支持动态索引,可以满足未来引入权限后,高权限内容不被低权限用户搜索到的需求。
我一看:行啊,有灵性!放手让它重新用 Fuse.js 来实现。
这一次虽然不是一击命中,但也还算顺利,初步完成了我的需求,在这个过程中我也简单了解了一下它用到的字符串模糊匹配算法和相关参数配置,以优化搜索结果。甚至还直接让它支持了 extended search
语法。
发布一版后,我自行也摆弄了一会儿,就感觉搜索结果不太符合我的直觉。跟我之前集成 Pagefind 的效果,差距甚大。并且在了解完算法细节和试过不同的参数组合之后,我也没能找到一个比较满意的结果。
第三次选型:灵光乍现,我让 Claude Code 重新拥抱 Pagefind
在郁闷了一段时间之后,我随手翻了翻 Pagefind 的文档(之前没读过,懒得看),突然灵光乍现:何不直接干预 Pagefind 的索引生成过程,这样两个问题都可以解决:
- 没有静态生成的文件,那就直接给它原始内容。
- 要解决权限问题,何不针对不同的权限生内容成不同的索引。一个团队技术站点,这种方式完全可以接受。
想通之后,我立刻让 Claude Code 查阅 Pagefind 的文档,同时把我的想法告诉它,让它重新评估并计划。最终,它同意了我的想法,将现有基于 Fuse.js 的实现改写成基于 Pagefind 的方式。经过简单测试,效果果然大有改观。
注:在此方式下 astro-pagefind 几乎没什么用,Claude Code 也没有用它。
反思
回顾整个过程,我不禁哑然失笑:本来 Claude Code 已经自行决定了选型,但在我的指挥下绕了个远道,最终还是回到了原来的选型。
假若一开始不是急冲冲改弦易辙而是阅读一下 Pagefind 的文档,或许灵感可以来得更早一些,也就避免了这翻折腾。
当然,作为领导的我也要批评一下 Claude Code:
- 假若不是遇到传说中的降智问题,或许它一开始就已经替我想到了。
- 假若它要是有原则一点,作为从善如流的我,自然也会尊重它的决定。
总之,这里面的责任要各打五十大板,哈哈!