399文字
2分
編集

Pagefindをローカル開発時でも動作させる

Pagefindの利用例を調べると、開発時はダミーデータを渡している実装しか見つからなかったが、ダミーデータの作成やコード上の分岐が増えることが億劫だったため、開発時も本番相当のデータが表示されるようにした。

#Pagefindの大まかな仕組み

PagefindはビルドされたHTMLファイルに対して実行し、インデックスを生成することで高速な検索を実現している。

そのため、例えばAstroの場合は次のようにビルドコマンドにフックさせて、ビルド後にPagefindを実行する。

json
// package.json
{
    "scripts": {
        "build": "astro build && pagefind --site dist",
    }
}

#ローカルで本番相当のデータを表示する実装

次のように開発サーバー起動時にpagefindの生成を行い、結果をビルドディレクトリではなくpublicディレクトリに出力する。

json
// package.json
{
  "scripts": {
    "predev":  "astro build && pagefind --site dist --output-path public/pagefind",
    "dev": "astro dev",
  }
}

これにより開発サーバー起動時とビルド後の環境で全く同じ実装でコードが動作するようになる。

Astroでの実装例:

astro
// search.astro
<input placeholder="Search..." id="search" name="search">      
<div id="search-results"></div>

<script is:inline type="module">
  document.addEventListener("DOMContentLoaded", async () => {

    const pagefind = await import("/pagefind/pagefind.js")

    pagefind.init()
    pagefind.options({
      basePath: "/pagefind/",
      baseUrl: "/",
      indexWeight: 1,
      excerptLength: 60,
    })

    const input = document.querySelector("#search")
    const results = document.querySelector("#search-results")

    const search = async (query) => {
      const searchResults = await pagefind.search(query);
      results.innerHTML = ""
      searchResults.results.forEach(async (result) => {
        const resultElement = document.createElement("div")
        const data = await result.data();
        resultElement.innerHTML = `
          <article>
            <header>
              <h2 class="text-base">
                <a href="${data.url}">
                  ${data.meta.title}
                </a>
              </h2>
            </header>
            <p>
              ${data.excerpt}
            </p>
          </article>
        `
        results.appendChild(resultElement)
      })
    }
    
    input.addEventListener("input", async (e) => {
      const query = e.currentTarget.value
      search(query)
    });

    const initValue = input.value
    if (initValue) {
      search(initValue)
    }
  })

</script> 
編集