readブログをGatsbyに移行してからずっとサボっていたサイト内検索機能ですが、ゴールデンウィークで時間があったので実装してみました。当記事はAlgolia自体の知識がある前提で書いてます。Algolia自体の説明やMiddleman製サイトに検索機能を導入する話に関してはこちらの記事をご参照ください。EGGはじめに当記事はAlgoliaを用いた実現手段の紹介になります。他の手段(JSONファイルに記事データを出力してFuse.js等を用いて全文検索etc)との比較検討などはしていません。当記事で使用してる技術に関して、Gatsbyのドキュメントでも紹介されてるのでそちらも併せてご参照ください。GatsbyJS実装方針Middleman時代はフルスクラッチで作っていたのですが、スクラッチだと記事の内容も実装の手間も無駄にかさんでしまうので、楽に導入できるよう今回はAlgolia公式のライブラリを2つ使用します。InstantSearchこれらを利用することで導入コストをかなり抑えられました。記事をAlgoliaに登録する(gatsby-plugin-algolia)gatsby-plugin-algoliaのリポジトリはこちらです。queries記事執筆時のREADMEではサイト内のすべてのページを登録するような処理になっていますが、ブログ記事だけを登録したいのでGraphQLのクエリを変えました。当サイトではこんな感じで設定にしてあります。↑の結果をshallowなオブジェクトの配列に整形transformerオプションには「オブジェクトの配列を返す必要がある」「配列の各要素はidという名前のフィールドをもつ必要が有ります」という2点の制約が有ります。idフィールドはすべての記事において一意な任意の文字列を指定できます。個人的に自動生成される値ではなくcontrollableな値が好きなのでslugをidにしました。それ以外のフィールドや構造に制約はなく、返却したオブジェクのすべてのフィールドがAlgoliaに登録されます。記事の本文を検索対象に含めたい場合、1objectあたりのサイズ制限を突破するために複数のチャンクにちぎって送信するなどの工夫が必要ですが、そもそも本文を検索対象に含めることはAlgoliaが非推奨だと言ってるので本文を含めないように設定しました。buildを実行すると、記事の一覧がAlgoliaに登録されます。うまく行かない場合、transform関数がオブジェクトの配列を返せているか確認しましょう。InstantSearch)Algoliaに記事を登録して検索できるようになったので、フロントエンドを作ります。InstantSearchを利用します。InstantSearchとはInstantSearch.jsというAlgoliaが提供している検索用UI用のコンポーネントのReact版です。InstantSearchを利用することで、Algoliaの検索ロジックや状態管理をスクラッチで実装する必要がなくなり、検索UIと検索結果の見た目を作ることだけに注力できます。(codesandbox)を見てみると、複雑な検索UIにも対応できるようです。React版を使って実装してみて、UIの自由度やカスタマイズ製も高くかなり使いやすかったので採用しました。動作デモ・コード当サイトの右上にある検索窓が触れるデモです。チューニングやパラメータの最適化などしていませんが、えげつない速度で検索結果が表示されます。スクショとしてはこんな感じです。コードはこちら(OnSiteSearchコンポーネント)を読むとInstantSearchコンポーネントとwidgetsの使い方がわかると思います。InstantSearchのドキュメントhttps://www.algolia.com/doc/api-reference/widgets/instantsearch/react/これを読みつつお好みでウィジェットを足していく感じになると思います。基本的にドキュメント見ながらやるだけなんですが、実装してて思った注意事項を以下に残します。KEYなどを環境変数に逃がしたくなると思います。GatsbyにはwebpackのDefinePluginが入っているので、ちょっと設定をしてあげれば各設定値を環境変数に逃がせます。Qiita未入力のときは検索結果を表示したくないデフォルトのウィジェットだけで検索UIを組むと、何も入力してない状態でも検索結果が表示されていると思います。サイト内検索では何か入力したときだけ結果を表示するためカスタマイズしました。connectStateResultsというHoCがexportされているので、それを利用してStateに対する見た目を制御できます。詳しくはドキュメント参照。こちらのドキュメントに検索結果が空の場合、エラーハンドリングについても記載が有ります。DocumentationAlgoliaのロゴを表示したいこちら(OnSiteSearchHitListコンポーネント)のように実装しました。InstantSearchのPanelコンポーネントを利用してヘッダとフッタを作り、フッタにPoweredByコンポーネントを表示してCSSでちょっと見た目を調整しました。CSSに関してはこちらをご参照ください。さいごにGatsby製サイトに検索機能を追加するときの参考になれば幸いです。スクラッチで作るよりはるかに簡単に導入できた(デバッグ含めて3hくらい)ので、Gatsbyのようにエコシステムが充実しているものに乗っかるのは正義だなと思いました。