
このブログのサイト内検索を、Google検索(site:)からPagefind
に移行しました。
Hugoで生成したpublic/をビルド後にPagefindでインデックス化し、静的サイト内で検索が完結する構成にします。
なぜGoogleのsite:検索が当てにならなくなったのか
このブログはHugo
で生成した静的サイトで、Cloudflare Pages
でホスティングしています。以前はナビゲーションバーにGoogleの検索フォームを設置して、site:blog.tumf.devでサイト内検索っぽく使っていました。
| |
この仕組みは「Googleが自サイトをインデックスしている」ことが前提です。インデックス状況に左右されると、検索結果が空になることがあります。
静的サイト検索の選択肢
Googleに依存しない検索方法を調べたところ、主に以下の選択肢がありました:
| 方法 | 特徴 | 日本語対応 | コスト |
|---|---|---|---|
| Algolia | 高機能・高速 | ✅ 良好 | 有料(無料枠あり) |
| Lunr.js | 軽量・クライアント検索 | ⚠️ 弱い | 無料 |
| Fuse.js | ファジー検索 | ✅ 良好 | 無料 |
| Pagefind | 静的・低帯域 | ✅ 対応 | 無料 |
個人ブログで有料のAlgoliaは避けたい。Lunr.jsは日本語の分かち書き(単語分割)が弱い。Fuse.jsは良さそうだが、Hugoとの統合例が少ない。
最終的にPagefindを選んだ理由は以下の通りです:
- 完全静的 - サーバー不要、Cloudflare Pagesと相性が良い
- 低帯域 - 検索時に必要なチャンクだけを読む設計
- 日本語対応 - CJK言語の分かち書きに対応
- 導入例が多い - 静的サイトでの採用例が多く、情報が見つけやすい
Pagefindの仕組み
Pagefindは「ビルド後にインデックスを生成する」アプローチを取ります。
| |
生成されたインデックスはpublic/pagefind/ディレクトリに配置され、検索時にJavaScriptで読み込まれます。
インデックスサイズの最適化
Pagefindの特徴は「検索時に必要な部分だけ読み込む」点です。全文検索インデックスを複数のチャンクに分割し、検索クエリに応じて必要なチャンクのみをダウンロードします。
このブログ(約135記事)の場合:
Indexed 135 pages
Indexed 10,376 words
Created 27 index chunks
27個のチャンクに分割され、検索時に必要なチャンクだけが読み込まれるため、検索のために全インデックスをまとめてダウンロードせずに済みます。
導入手順
1. package.jsonの作成(任意)
Pagefindはnpmパッケージとして提供されているため、継続運用するならpackage.jsonに入れておくと楽です。毎回npxで実行するだけなら、このステップは省略できます。
| |
2. HTML要素にdata属性を追加
Pagefindはdata-pagefind-body属性で検索対象を指定します。記事テンプレート(layouts/_default/single.html)を修正:
| |
記事タイトルにはdata-pagefind-meta="title"を追加(layouts/partials/post_header.html):
| |
3. 検索UIの追加
Pagefindは検索UIをプリビルドで提供しています。ナビゲーションバーに検索ボックスを追加(layouts/partials/pagefind-search.html):
| |
4. インデックス対象の制限
デフォルトでは全HTMLファイルがインデックスされますが、下書きや一覧ページは除外したいため、pagefind.ymlで設定:
| |
これでposts/配下の記事のみがインデックスされます。
5. 未来日付の記事を除外
Hugoはデフォルトで未来日付や下書きをビルドしませんが、CI/CDの設定やビルドフラグで含めている場合は、明示的に無効化しておくと安心です。
| |
6. Cloudflare Pagesのビルド設定
Cloudflare Pagesのビルドコマンドを以下に変更:
| |
または
| |
日本語検索の制限と対策
Pagefindは日本語の分かち書き(単語分割)に対応していますが、いくつか制限があります。
制限1: ステミング未対応
英語では「running」を検索すると「run」もヒットしますが、日本語では「走る」「走った」「走っている」を個別に検索する必要があります。
制限2: 検索語によっては工夫が必要
インデックス時に分かち書きされるため、検索語によってはスペース区切りにするとヒットしやすくなる場合があります。
対策: 検索ヒント
検索ボックスのプレースホルダーを「Search」にして、日本語でも英語でも検索できることを示しています。また、検索結果が0件の場合は「スペース区切りで試してください」といったヒントを表示することも検討できます。
デザインの調整
Pagefind UIはデフォルトでモダンなデザインですが、既存のテーマに合わせるためCSSをカスタマイズしました。
元のGoogle検索フォームのスタイルを踏襲
元のテーマ(Octopress)では、検索ボックスは以下のスタイルでした:
| |
Pagefind UIのスタイルを上書きして、同じ見た目に調整:
| |
検索結果のドロップダウン
検索結果はナビゲーションバーの下にドロップダウンで表示されるようにしました:
| |
まとめ
Google検索(site:)からPagefindへの移行は、想像以上にスムーズでした。
良かった点:
- 完全静的なので、Googleのインデックス状況に依存しない
- 低帯域で高速(検索時に必要なチャンクだけ読み込む)
- 日本語検索が実用レベル
- デザインのカスタマイズが容易
注意点:
- 日本語のステミングは未対応
- 検索語によってはスペース区切りにするとヒットしやすい場合がある
- ビルド時にインデックス生成が必要(ビルド時間が若干増加)
個人ブログや技術ドキュメントサイトで「Googleに頼らない検索」を実現したい方には、Pagefindは良い選択肢だと思います。