🔍

Astro + Pagefindでブログに検索機能を実装する

2024/01/13に公開

静的サイト向けの検索ライブラリ Pagefind安定版(v1.0.0)がリリースされた のでAstroと一緒に使ってみます。

Pagefindは大規模なサイトでも高速に動作し、帯域幅も最小限にすると謳っていて、HTMLファイルを読み込んでインデックスを作成、検索UIもデフォルトで提供される検索用ライブラリです。通常のフレームワークのビルド成果物を対象にインデックスを生成するので、とても簡単に導入することができます。

また、今回の記事で作成したプロジェクトのソースコードはs7tya/astro-pagefind-playgroundにて公開しています。

Pagefind のインストール

デフォルトのテンプレートで作成した新規Astroプロジェクトをベースに、Pagefindを設定していきます。

pagefind @pagefind/default-ui パッケージを追加します。

$ npm add pagefind @pagefind/default-ui
$ npm run build

Astroの場合、デフォルトでは dist/ 配下にビルドした成果物が配置されます。そのため、Pagefindを dist/ をオプションに指定して Pagefind のインデックスを作成します。

$ npx pagefind --site dist

数秒でインデックスが作成されます。無事にインデックスが貼れたら検索のためのUIを実装しましょう。

検索UIの追加

@pagefind/default-ui のREADME を参考に、Search.astro を作成します。

src/components/Search.astro (new)
---
import "@pagefind/default-ui/css/ui.css";
---

<div class="search"></div>

<script>
  import { PagefindUI } from "@pagefind/default-ui";

  new PagefindUI({
    element: ".search",
  });
</script>

手元では / の一番上に検索フォームを追加してみました。

src/pages/index.astro
  ---
  (省略)
+ import Search from "../components/Search.astro";
  ---

  <Layout title="Welcome to Astro.">
+   <Search />
  (省略)
  </Layout>
`@pagefind/default-ui` の型定義

TypeScriptを使用している場合、 @pagefind/default-ui には型定義が存在しないためエラーが発生します。そのため、 src/env.d.ts に以下を追記してください。

(型もざっくりと付けただけなので、適宜修正してください。)

declare module "@pagefind/default-ui" {
    declare class PagefindUI {
        constructor(opts: {
            element?: string | HTMLElement,
            bundlePath?: string,
            pageSize?: number,
            resetStyles?: boolean,
            showImages?: boolean,
            showSubResults?: boolean,
            excerptLength?: number,
            processResult?: any,
            processTerm?: any,
            showEmptyFilters?: boolean,
            debounceTimeoutMs?: number,
            mergeIndex?: any,
            translations?: any,
            autofocus?: boolean,
            sort?: any,
        })
    }
}

これで検索機能が動作するようになりました。このままだとAstroのデフォルトスタイルの影響で背景が黒く、検索結果が見づらいので少しだけスタイルをつけます。

<style>
  .search {
    transition-duration: 300ms;
    background: white;
    border-radius: 8px;
  }

  .search:not(:has(.pagefind-ui__hidden)) {
    padding: 16px;
    border-radius: 16px;
  }
</style>

完成物

完成です!本当に簡単・高速に検索が設定できてしまいました。日本語での挙動などを試せていないので現時点でどのくらい実用に耐えるのかは分かりませんが、Pagefindには期待大です。

Discussion