小Z的个人空间

静态博客如何实现搜索功能

PageFind搜索静态博客Hugo

静态博客如何实现搜索功能

静态博客(Hugo、Jekyll、Hexo 之类)最大的痛点之一就是没有搜索功能。WordPress 有插件,但静态博客没有数据库,怎么搜?

常见方案对比

最省事的方案,直接用搜索引擎站内搜索:

<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 工作原理

  1. 编译阶段:Hugo 生成 HTML 后,运行 pagefind --site public,PageFind 会爬取所有 HTML 文件,建立倒排索引,生成一批二进制文件(.pf_index.pf_meta 等)
  2. 运行时:浏览器加载 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 站内搜索体验好很多。