静的サイト内検索

pluginSearch()はページの本文から検索用JSONを生成します。検索UIはブラウザでこのデータを読み込むため、検索用サーバーや外部サービスを用意せずに使えます。

Islandの設定を利用して、サイト内のお知らせを検索できるようにします。

Table of Contents

プラグインを追加する

検索UIはIslandとして動作します。pluginSsg()に加え、pluginIsland()とpluginSearch()を追加します。

vite.config.ts
import { defineConfig, pluginSsg, pluginIsland, pluginSearch } from "minista"

export default defineConfig({
  plugins: [pluginSsg(), pluginIsland(), pluginSearch()],
})

検索対象の本文を指定する

検索に含める領域へdata-searchを付けます。ナビゲーションやフッターは、その外側へ置きます。検索結果のタイトルにはHTMLのtitleが使われます。

src/pages/news/hello.tsx
import { Head } from "minista/head"

export default function Article() {
  return (
    <>
      <Head>
        <title>スタジオを開設しました</title>
      </Head>
      <article data-search>
        <h1>スタジオを開設しました</h1>
        <h2 id="equipment">スタジオの設備</h2>
        <p>撮影スタジオに新しい照明を導入しました。</p>
      </article>
    </>
  )
}

見出しにIDを付けると、検索結果から本文中の位置へ移動できます。Markdown・MDXのページなら、共通レイアウトで本文をdata-search付きの領域に包む構成も使えます。

検索UIを配置する

src/pages/search.tsx
import { Search } from "minista/assets"

export default function SearchPage() {
  return (
    <>
      <h1>サイト内検索</h1>
      <Search
        client:load
        field={{ placeholder: "キーワードを入力" }}
        maxHitPages={10}
      />
    </>
  )
}

Searchは検索フィールドと結果一覧を出力します。client:loadを付けて操作できるようにし、見た目はCSSで調整してください。

ビルドして検索する

プロジェクト構成
src/pages/
├── index.tsx
├── search.tsx
└── news/
    └── hello.tsx
ビルド結果の例
dist/
├── index.html
├── search.html
├── news/
│   └── hello.html
└── assets/
    ├── search-[hash].json
    └── ...(検索UIのJavaScriptなど)

npm run buildとnpm run previewを実行し、/searchで「スタジオ」を入力します。検索データは初回の入力時に取得されます。本文を更新したときは、HTMLと検索JSONを再ビルドして一緒に公開します。

検索範囲を絞る

srcとignoreは出力先を基準にしたHTMLファイルのglobです。例えばお知らせだけを対象にする場合は、次の設定を使います。

pluginSearch({
  src: ["news/**/*.html"],
  ignore: ["news/draft.html"],
  ignoreSelectors: ["h1", ".navigation"],
  trimTitle: " - My Site",
})

ignoreSelectorsは本文中の不要な要素、trimTitleは検索結果のタイトルから取り除く文字列を指定します。

生成データに採用する単語はhitで調整します。短い日本語の語句も対象にしたい場合は、hit.minLengthを下げられます。これはUIが検索を始めるminHitLengthとは別の設定です。

pluginSearch({ hit: { minLength: 2, hiragana: true } })

複数の検索インデックス

多言語サイトや、ブログとドキュメントで対象を分ける場合はindexesを指定します。

pluginSearch({
  indexes: {
    docs: { src: ["docs/**/*.html"] },
    news: { src: ["news/**/*.html"] },
  },
})
<Search index="docs" client:load />

この例ではsearch-docsとsearch-newsを基にした二つのJSONが出力されます。UIのindexを明示して対象を選びます。URLによる自動判定はありません。

インデックスごとの設定継承、検索UIのprops、JSONの形式はpluginSearchを参照してください。

次はHTMLコメントで生成HTMLに区切りや補足を残します。