静态博客如何实现搜索功能
静态博客(Hugo、Jekyll、Hexo 之类)最大的痛点之一就是没有搜索功能。WordPress 有插件,但静态博客没有数据库,怎么搜?
常见方案对比
1. Google Search / Bing Search
最省事的方案,直接用搜索引擎站内搜索:
<form action="https://www.google.com/search" method="get">
<input type="hidden" name="q" value="site:aizsx.com">
<input name="q" placeholder="搜索...">
</form>
优点:零成本、零配置。缺点:依赖搜索引擎、有广告、结果不精准、无法自定义 UI。
2. Algolia DocSearch
Algolia 提供的免费文档搜索服务,需要申请,审核通过后会给你一个搜索框代码。
优点:搜索体验好、支持中文。缺点:要申请、有配额限制、国内访问不稳定。
3. PageFind
今天博客里实际用的方案。核心思路是:编译时生成搜索索引,浏览器端执行搜索,完全不依赖任何后端服务。
优点:
- 纯静态,搜索全在浏览器里完成
- 索引在服务端生成,不占用客户端资源
- 支持按范围过滤(标题、标签、正文)
- 免费开源
缺点:
- 索引文件会增加一些体积
- 每次发布文章需要重新生成索引
PageFind 工作原理
- 编译阶段:Hugo 生成 HTML 后,运行
pagefind --site public,PageFind 会爬取所有 HTML 文件,建立倒排索引,生成一批二进制文件(.pf_index、.pf_meta等) - 运行时:浏览器加载
pagefind.js(约 30KB),JS 读取索引文件,执行搜索逻辑
索引文件会被浏览器缓存,第二次访问速度会快很多。
Hugo + PageFind 实现步骤
步骤 1:安装 PageFind
npm install -g pagefind
步骤 2:标记要索引的内容
在 Hugo 主题的 single.html 文章模板里,给 <article> 标签加属性:
<article data-pagefind-body>
<h1 data-pagefind-meta="title">{{ .Title }}</h1>
...
</article>
data-pagefind-body 表示这是文章正文,需要索引。data-pagefind-meta 可以标记元数据(标题、标签等),用于后面实现分类搜索。
步骤 3:生成索引
hugo
pagefind --site public
步骤 4:写搜索页面
在 content/search/index.md 创建搜索页,在模板里用 PageFind JS API 渲染搜索框和结果。关键代码:
import { search, init } from '/pagefind/pagefind.js';
const res = await search('关键词');
const d = await res.results[0].data();
console.log(d.url, d.excerpt); // 链接和摘要
步骤 5:部署时同步索引
pagefind --site public 生成的 pagefind/ 目录要一起部署到服务器。我把它加到了 deploy.sh 里,每次发布自动生成索引并同步。
搜索范围过滤的实现
PageFind 默认是全文搜索,我想支持"只搜标题"或"只搜标签",这个要自己写过滤逻辑。
思路:用 PageFind 搜索拿到全部结果,然后逐条调用 result.data() 获取元数据,根据元数据做过滤:
if (scope === 'title') {
if (!d.meta.title.includes(keyword)) return;
}
if (scope === 'tag') {
if (!d.meta.tag.some(t => t.includes(keyword))) return;
}
这本质上是先全量搜索再在客户端过滤,体验上没问题,因为 PageFind 索引本身很小,搜索是毫秒级的。
总体来说,PageFind 是目前最适合个人静态博客的搜索方案。零成本、零依赖、效果够用,比 Google 站内搜索体验好很多。