背景
本站使用 Hugo + PaperMod,通过 Containerfile 构建为 Nginx 静态站点镜像。文章约 2800+ 篇(Pagefind 实测索引 2779 页)。本文记录站内搜索方案调研与当前 Pagefind 接入方式。
PaperMod 内置搜索(Fuse.js,已弃用)
PaperMod 主题自带基于 Fuse.js 的客户端搜索:Hugo 构建时生成 index.json,搜索页在浏览器里加载全文索引并做模糊匹配。零后端依赖,但本站实测 index.json 约 13MB,需一次下载全部正文,首访慢,中文分词也一般。现已移除 Fuse 相关配置,改用 Pagefind。
Hugo 静态站搜索方案对比
| 方案 | 原理 | 适合规模 | 优点 | 缺点 |
|---|---|---|---|---|
| PaperMod Fuse.js | 浏览器加载完整 JSON | 小站(约 500 篇以内) | 零配置、纯静态 | 大站索引体积大、首访慢;中文分词弱 |
| Pagefind | 构建时生成索引,搜索时按查询加载分片 | 中大型站 | 首访不必下完全部正文;extended 支持 CJK | 需加构建步骤;索引目录总体积未必更小 |
| Lunr.js | 类似 Fuse,浏览器建倒排索引 | 小中型 | 多主题支持 | 与 Fuse 同类局限 |
| Algolia DocSearch | 构建时推送到 Algolia 云端 | 文档站 / 开源项目 | 搜索体验好 | 需申请、依赖第三方 |
| Meilisearch / Typesense | 自托管搜索引擎 | 大型站 | 功能强 | 需跑服务,个人博客偏重 |
本站实现:Pagefind
采用 Pagefind extended(v1.5.2,支持中文分词)。搜索 UI 使用 Default UI(pagefind-ui.js / PagefindUI),不是 1.5 新推荐的 Component UI。
构建流程
flowchart LR
A[hugo --minify] --> B[public/*.html]
B --> C[pagefind --site public]
C --> D[public/pagefind/]
D --> E[/search/ 搜索页]
统一入口:scripts/build-site.sh(task site:build)。
- 本地:脚本内
npx -y pagefind@1.5.2(npm 包默认带 extended) - Cloudflare Pages:
build.sh→scripts/build-site.sh(OpenTofubuild_command = "bash build.sh") - 容器:
Containerfile安装pagefind_extended二进制,执行hugo --minify && pagefind --site public
索引范围
文章 URL 在站点根路径(front matter 自定义 url),不在 /post/ 下,因此不能用 post/**/*.html 这类 glob 限定范围。
实际做法:
pagefind.yml只指定site: publiclayouts/single.html在<article>上加data-pagefind-body- Pagefind 检测到该属性后,自动忽略不含它的页面(标签页、分类列表、首页等)
post-footer等区域加data-pagefind-ignore,避免标签链接等进入正文索引
关键文件
| 文件 | 作用 |
|---|---|
content/search.md |
搜索页内容,layout: search |
pagefind.yml |
指定索引源目录 public |
layouts/single.html |
文章页 data-pagefind-body;页脚 data-pagefind-ignore |
layouts/search.html |
搜索页挂载 PagefindUI |
layouts/_partials/head.html |
移除 PaperMod Fuse.js 脚本 |
assets/css/extended/pagefind.css |
搜索框样式适配 PaperMod 主题色 |
scripts/build-site.sh |
hugo + pagefind,版本由 PAGEFIND_VERSION 控制 |
build.sh |
Cloudflare Pages 入口:生成 stats.json 后调用 scripts/build-site.sh |
Containerfile |
多阶段构建:Hugo → Pagefind → Nginx |
config.toml |
启用「搜索」菜单;outputs.home 仅保留 HTML(不再生成 index.json) |
本地预览
| 命令 | 说明 |
|---|---|
task preview |
hugo server 热更新(:1313),无搜索索引 |
task preview:search |
先 build-site.sh 构建索引,再 pagefind --serve 静态服务(:1414);非热更新 |
task site:build |
仅构建到 public/,不启动服务 |
访问搜索页:http://localhost:1414/search/(preview:search)或部署后的 /search/。导航栏「搜索」、Alt + / 快捷键可用。
与 Fuse 方案的区别
| Fuse.js(旧) | Pagefind(当前) | |
|---|---|---|
| 索引产物 | index.json(约 13MB 全文) |
public/pagefind/(约 27MB,压缩分片) |
| 加载方式 | 打开搜索页一次下载全部 | 按查询按需加载相关分片 |
| 构建步骤 | 仅 hugo |
hugo + pagefind |
| 收录范围 | index.json 遍历 RegularPages |
仅含 data-pagefind-body 的 HTML(实测 2779 页) |
| 中文 | 字符级模糊匹配 | extended 版 CJK 分词 |
索引目录总体积未必小于 Fuse 的单文件 JSON,优势在于搜索时不必首屏拉取全部正文。