返回书卷列表
Notes

Pagefind:纯静态站点的全文搜索

2 分钟阅读

构建期索引、客户端零请求检索——Pagefind 的工作原理、中文分词处理与构建脚本的接入方式

#pagefind#search#static-site#performance

Pagefind:纯静态站点的全文搜索

给静态博客加搜索,传统方案是生成一个几百 KB 的 JSON 索引让浏览器下载。Pagefind 换了个思路:索引在构建期生成,切片存放,浏览器按需加载——搜索时实际下载的往往只有几十 KB。

工作原理

npx pagefind --site out

构建后跑一条命令,Pagefind 扫描 out/ 里的 HTML,按页面提取内容,把倒排索引切成小块存在 /pagefind/ 目录。每个块覆盖一部分词项,用户输入查询时,客户端只加载「包含这些词」的块,按需渐进加载。文章越多,这个按需加载的优势越明显——全量索引方案是文章翻倍、下载体积翻倍,Pagefind 几乎不变。

中文分词

Pagefind 对 CJK 的支持不需要额外配置:构建期它把中文文本按字/词切分进索引,检索「静态导出」能命中包含「静态导出部署」的段落。实测两个注意点:一是混合中英文的文章,英文词按词干匹配,中文按切分匹配,两边都能查;二是标题的权重天然高于正文,把关键词放进标题对搜索排序的提升比堆在正文里大得多。

与其他方案的分工

本站现在有两套检索:Pagefind 管关键词,站内问答(RAG)管自然语言。分工标准很朴素——「我记得写过什么东西」用搜索,能精确命中关键词;「这个配置为什么这么设」用问答,需要语义理解。两者共用同一批文章,互不替代。

接入构建脚本

{
  "scripts": {
    "build": "next build && npx pagefind --site out"
  }
}

顺序必须是 next build 之后再跑 Pagefind——它索引的是构建产物而不是源码。CI 里的 E2E 因此有个隐性依赖:跑搜索断言前必须确认 Pagefind 已执行,否则 /pagefind/pagefind.js 是 404,搜索框永远转圈。

客户端接入

const pagefind = await import('/pagefind/pagefind.js');
await pagefind.search('向量检索');
// 返回结果带 excerpt 与跳转 URL

动态 import 很关键:搜索框没打开前不加载任何索引代码。Pagefind 的 UI 组件可以开箱即用,但自建对话框的好处是样式与站点主题一致——本站搜索、问答两个弹窗共用一套交互范式,就是自建的理由。

性能数字

构建 12 篇文章的索引约 1 秒;/pagefind/ 目录总计约 300 KB,单次查询实际加载 20-40 KB;查询响应在低端设备上也在 10ms 量级。对比运行时搜索方案(每次请求打后端或加载全量索引),这个数字没有悬念。

基于站内文章回答,并标注引用来源

留言

加载中…

0/500