Gatsby.jsで作る静的サイトにAlgoliaの検索システムを導入する
Algoliaは、超高速のサイト内検索を実現する、同名の会社の検索エンジン製品です。
さまざまなサイトに採用されており、エンジニアの方であればドキュメンテーション系でAlgoliaのロゴをご覧になったこともあると思います。Gatsby.jsのドキュメントでも採用されていますね。
Google Custom Searchは導入の敷居は低いですが、せっかくのJamstackサイトがGoogleのスクリプトで重くなってしまうため、今回このAlgoliaをGatsby.jsサイトに導入してみました。
動作環境:
- Node.js v20.14.0
- React v18.3.1
- Gatsby.js v5.13.7
- gatsby-plugin-algolia v1.0.3
- algoliasearch v5.0.0
- react-instantsearch v7.12.4
ざっくり4ステップです。
- Algoliaへのアカウント登録・プロジェクト側の設定
- 検索用データの生成・保存
- 検索結果をサイトに表示する機能の構築
- スタイルを整える
尚、今回の例では「Markdownのブログを検索させる」前提とします。ヘッドレスCMSからGraphQLクエリを引っ張ってきている場合は、クエリの取得部分をご自身の状況に合わせて書き換えてください。
Algoliaにアカウント登録
まずはAlgoliaにサインアップし、新規のインデックスデータの名前を作ります。インデックス名は、運用環境によりdev_
やtest_
、prod_
などの接頭語をつける旨が公式でアドバイスされています。
インデックス名を登録したら、「2. Configure search relevance」を無視して、左下の⚙️Settings -> API Keysへ進みます。
「API Keys」ページで、必要なAPIキーを確認。必要なのは、上から3つです。
- Application ID
- Search-Only API Key
- Admin API Key
これらは後に必要になるため、Algoliaの画面はとりあえずこのままにしておきます。
Gatsby.js用のAlgolia公式プラグイン(検索データ作成用)
Algoliaが用意しているGatsby.js用のプラグイン、gatsby-plugin-algoliaをインストール。
# npmの場合
npm install gatsby-plugin-algolia
# yarnの場合
yarn add gatsby-plugin-algolia
インストールが完了したら、gatsby-config.jsにプラグイン情報を追記します。
require("dotenv").config({
path: `.env.${process.env.NODE_ENV}`,
})
module.exports = {
//...
plugins: [
//...
{
resolve: `gatsby-plugin-algolia`,
options: {
appId: process.env.ALGOLIA_APP_ID,
apiKey: process.env.ALGOLIA_API_KEY,
indexName: process.env.ALGOLIA_INDEX_NAME,
queries: [
{
query: `{
// ここにクエリを追加
}`,
transformer: ({ data }) =>
data.allMarkdownRemark.edges.flatMap(({ node }) => {
return {
// ここにクエリからAlgoliaに登録するオブジェクトを記載
}
}),
},
],
chunkSize: 10000,
},
},
],
}
先ほどのAlgoliaのページで確認したAPIキーのうち、アプリケーションID・Admin API Keyの2つと、作成したインデックス名を環境変数として使用します。.env.production
ファイルに記載。
ALGOLIA_APP_ID=[Application ID]
ALGOLIA_API_KEY=[Admin API Key]
ALGOLIA_INDEX_NAME=[your_index_name]
検索データの構築はビルド時にのみ動くので、.env.development
には記載不要です(ALGOLIA_INDEX_NAME
のみあとで使用)。
検索用データを生成してAlgoliaに送る
検索用データ生成ようのAlgolia製Gatsby.js用プラグイン
Algoliaを使うには、Algolia上にあらかじめ検索用のデータを保存しておく必要があります。データ構築・保存作業に使うのが、先ほどインストールしたgatsby-plugin-algoliaです。
gatsby-config.js
のプラグイン情報に、Algoliaに保存したいインデックスデータのクエリを追記すれば、もう動きます。
とは言え、「何を検索データとしてAlgoliaに保存しておきたいか」が重要です。不要なデータもコストを消費してしまうため、厳選しましょう。
当記事の例では、MarkdownのYAML Frontmatterデータから、以下を利用することにします。
- タイトル
- スラッグ(IDとして使用)
- 抜粋文
- カテゴリー
Algoliaに送るクエリはこうなりました。
module.exports = {
//...
plugins: [
//...
{
resolve: `gatsby-plugin-algolia`,
options: {
appId: process.env.ALGOLIA_APP_ID,
apiKey: process.env.ALGOLIA_API_KEY,
indexName: process.env.ALGOLIA_INDEX_NAME,
queries: [
{
query: `{
allMarkdownRemark {
edges {
node {
frontmatter {
title
slug
description
categories
}
}
}
}
}`,
transformer: ({ data }) =>
data.allMarkdownRemark.edges.flatMap(({ node }) => {
return {
objectID: node.frontmatter.slug,
excerpt: node.frontmatter.description,
title: node.frontmatter.title,
categories: node.frontmatter.categories.map(
category => category.title
),
}
}),
},
],
chunkSize: 10000,
},
},
],
}
AlgoliaではobjectID
がデータ管理に使われており、objectID
を基準に差分判定がされます。
今回はスラッグをobjectID
にしていますが、スラッグが変更になると、差分判定にムダが出てしまいます。スラッグが頻繁に変わる可能性がある場合は、他のデータを充てるようにしてください。
ビルドをして検索用データをAlgoliaに送る
ここまでで、検索用データの構築・Algoliaへ送信の準備が整いました。
ローカル上でビルドをしてみて、ビルドの終盤にAlgoliaへデータ送信が行われた旨が表示されれば完了です。
gatsby build
...
success index to Algolia - 10.728s - Done!
...
Algoliaのダッシュボードを見ると、インデックスにデータが保存されているのが確認できます。
クエリにimage:url
含めて送れば、画像を登録することも可能です。
検索結果を表示させる
次に、検索結果をサイト上で表示するための作業を行います。
ライブラリのインストール
検索結果を表示するために使うライブラリは、react-instantsearchです(React v16.8.0以上)。algoliaseachも必要なので、同時にインストールします。
# npmの場合
npm install algoliasearch react-instantsearch
# yarnの場合
yarn add algoliasearch react-instantsearch
Algoliaはこれまで複数の同様のライブラリをリリースしており、上記react-instantsearchが2023年22月時点の最新型となっています(重要ポイント)。
公式ドキュメントではこれまでのすべてのライブラリの情報が収められている上、別々のライブラリでも同じ名前のコンポーネントがあるので(互換性もあったりなかったり)、ドキュメント検索時には注意が必要です。
当エントリーを参考にしてAlgoliaを導入する場合は、ドキュメント検索時に画面右下のライブラリ名が「React InstantSearch v7」になっているかを確認してください。
検索結果を表示させる
componentsフォルダーに、algolia.jsというファイルを用意。以下のコードは、検索結果を表示させるための基本の形です。
import React, { useMemo } from "react"
import { algoliasearch } from "algoliasearch"
import { InstantSearch } from "react-instantsearch"
const Algolia = () => {
const searchClient = useMemo(
() =>
algoliasearch(
process.env.GATSBY_ALGOLIA_APP_ID,
process.env.GATSBY_ALGOLIA_SEARCH_KEY
),
[]
)
return (
<InstantSearch
searchClient={searchClient}
indexName={process.env.ALGOLIA_INDEX_NAME}
>
{/* ここにウィジェット */}
</InstantSearch>
)
}
export default Algolia
searchClient
はuseMemo()
によりメモ化して、再レンダリングしパフォーマンス向上を図ります(参考)。
環境変数を.env.development
と.env.production
の両方に記載。
ALGOLIA_INDEX_NAME=[your_index_name]
GATSBY_ALGOLIA_APP_ID=[Application ID]
GATSBY_ALGOLIA_SEARCH_KEY=[Search-Only API Key]
※ALGOLIA_INDEX_NAME
は先ほど書いたものと同じ
検索ボックスを作る
検索ボックスは、SearchBoxというウィジェットを利用。
import React, { useMemo } from "react"
import { algoliasearch } from "algoliasearch"
import { InstantSearch, SearchBox } from "react-instantsearch"
const Algolia = () => {
const searchClient = useMemo(
() =>
algoliasearch(
process.env.GATSBY_ALGOLIA_APP_ID,
process.env.GATSBY_ALGOLIA_SEARCH_KEY
),
[]
)
return (
<InstantSearch
searchClient={searchClient}
indexName={process.env.ALGOLIA_INDEX_NAME}
>
<SearchBox />
</InstantSearch>
)
}
export default Algolia
このAlgoliaコンポーネントを他のコンポーネントやテンプレート内で使えば、サイト上に検索ボックスが表示できます。
検索結果表示部分を作る
検索結果表示には、Hitsというウィジェットを利用。
import React, { useMemo } from "react"
import { algoliasearch } from "algoliasearch"
import { InstantSearch, SearchBox, Hits } from "react-instantsearch"
const Algolia = () => {
const searchClient = useMemo(
() =>
algoliasearch(
process.env.GATSBY_ALGOLIA_APP_ID,
process.env.GATSBY_ALGOLIA_SEARCH_KEY
),
[]
)
const Hit = ({ hit }) => {
return (
<Link to={`/blog/${hit.objectID}/`}>
<article>
<h1>{hit.title}</h1>
<p>{hit.excerpt}...</p>
<ul>
{hit.categories.map(category => (
<li>{category}</li>
))}
</ul>
</article>
</Link>
)
}
return (
<InstantSearch
searchClient={searchClient}
indexName={process.env.ALGOLIA_INDEX_NAME}
>
<SearchBox />
<Hits hitComponent={Hit} />
</InstantSearch>
)
}
export default Algolia
スタイルを整える
後はスタイルを整えるだけです。
- 独自クラス名を調整する
- ウィジェットに
classNames
またはclassName
プロパティを付与
Algoliaによるコードには独自クラス名が割り振られているので、そのクラス名を利用してスタイリングが可能です。
または、classNames``className
プロパティを使って、CSSモジュールやTailwind CSSなどでスタイリングすることもできます。
(本番前に)Gatsby.jsプラグインの調整
Algoliaへデータを送信しない設定
Algoliaへビルドの度に送信しないようにするには、dryRun
をtrue
にしておきます。
{
resolve: `gatsby-plugin-algolia`,
options: {
//...
dryRun: true,
}
}
この設定により、ビルドの最後にAlgoliaへのデータ送信が行われなかった旨が表示されます。
gatsby build
...
==== THIS IS A DRY RUN ====================
- No records will be pushed to your index
- No settings will be updated on your index
私の場合は、必要な時のみ「dryRun: false
」とし、通常のビルドではAlgoliaへ送信しないようにしています。
状況に応じて、どのポイントのビルドでインデックスをAlgoliaに送るかご判断ください。
参考サイト
- Algolia
- gatsby-plugin-algolia
- Adding Search with Algolia ※以前のライブラリ(react-instantsearch-dom)を使っている点には注意