Gatsby.js製のブログでAlgolia DocSearchを導入するときにハマったこと

Blog

Algoliaが提供するDocSearchを使うと、自作ブログに検索機能をつけることができます。
この記事では、Gatby.js製のブログにDocSearchを導入したときの、ハマったポイントとその解決方法を説明します。

動作を確認した環境

  • @docsearch/react v3
  • Gastby.js v4

ハマったこと1:Algolia Crawlerが利用可能になるまでに時間がかかりそう

Algoliaを使って検索機能を実装する場合、事前にAlgoliaの検索インデックスにブログのコンテンツを登録する必要があります。
自前で登録する仕組みを用意する代わりに、Algolia Crawlerというサービスを利用すると、定期的にインデックスに登録できます。
DocSearchを導入する場合、Algolia Crawlerも同時に利用できますが、申請が必要であり、チェックリストに該当していなければなりません。

技術ブログも申し込みできる対象になっていますが、利用可能になるまでには時間がかかりそうでした。
そのため、今回は自前でAlgoliaのインデックスを自前で登録することにしました。

Gatsby.js製のブログの場合、gastby-plugin-alogliaを導入すると、登録処理の部分を実装する必要がなさそうだったため、これを使うことにしました。
gatsby-config.jsを使うとサイトのビルド時にサイト内の情報をAlgoliaのインデックスに自動で登録するようになります。

導入はかんたんで、npmでインストールした後、gatsby-config.jsに設定を追記します。
Algoliaの環境設定は、環境変数から読み込むようにします。
このブログはNetlifyでホスティングしているため、Netlifyの環境にも設定します。

queriesの部分では、登録対象となる記事のコンテンツを抽出するクエリを指定します。
また、transformerで、抽出したコンテンツをAlgoliaのインデックスへ登録するプロパティの形式に変換します。

gatsby-config.js
module.exports = {
  // ...,
  plugins: [
    {
      resolve: `gatsby-plugin-algolia`,
      options: {
        appId: process.env.GATSBY_ALGOLIA_APP_ID,
        apiKey: process.env.ALGOLIA_API_KEY,
        indexName: process.env.GATSBY_ALGOLIA_INDEX_NAME,
        queries: [
          {
            query: `{
              allMdx {
                edges {
                  node {
                    excerpt
                    fields {
                      slug
                    }
                    frontmatter {
                      title
                      date(formatString: "YYYY-MM-DD")
                      tags
                    }
                  }
                }
              }
            }`,
            transformer: ({ data }) =>
              data.allMdx.edges.flatMap(({ node }) => {
                return {
                  id: node.fields.slug,
                  content: node.excerpt,
                  title: node.frontmatter.title,
                  publishedAt: new Date(node.frontmatter.date),
                  tags: node.frontmatter.tags,
                }
              }),
          },
        ],
        chunkSize: 10000,
      },
    },
  ],
  // ...
}

あとはGetting Startedを参考に、ヘッダーを表示するコンポーネントにDocSearchの検索窓のコンポーネントを設置すれば、検索ボックスが表示されます。

ハマったこと2:[object Object]が表示される

サイトをビルドし直して検索してみたところ、開発者ツールのコンソールに次のようなエラーが表示されてしまいました。

“Uncaught (in promise) TypeError: Cannot read property ‘lvl0’ of undefined”

どうやらDocSearchで検索するにはインデックスの属性にhierarchyというプロパティが必要で、Algolia Crawlerはこのプロパティを自動で登録しているようでした。
そのため、gastby-plugin-algoliaのインデックスへ登録するプロパティの形式に変換する箇所で、hierarchyプロパティが登録されるようにします。

hierarchyプロパティの属性には、lvl0からlvl6まで指定できます。
Ref. recordProps API Reference

この数字はドキュメントの階層構造にしたがっているため、今回はlvl0lvl1に記事のカテゴリーと記事のタイトルを渡すようにしました。
このブログのカテゴリは今のところ「Blog」固定なので、lvl0は固定値としています。

gatsby-config.js
            transformer: ({ data }) =>
              data.allMdx.edges.flatMap(({ node }) => {
                return {
                  id: node.fields.slug,
                  // ...
+                  hierarchy: {
+                    lvl0: "Blog",
+                    lvl1: node.frontmatter.title
+                  },
                }
              }),
          },

Algoliaのインデックスが生成し直した後にもう一度検索し直してみると、「Uncaught 〜」エラーは消えて検索結果が表示されるようになりました。

ハマったこと3:検索結果の一覧に「#」だけが表示されてしまう

検索結果は表示されるようになったものの、一覧には「#」だけが表示されています。

画面キャプチャ:検索結果に「#」だけが表示されている

調べたところ、インデックスにtypeというプロパティでどの値を一覧のタイトル部分表示するかを指定する必要があるようでした。
そのため、gastby-plugin-algoliaのインデックスへ登録するプロパティの形式に変換する箇所で、typeプロパティが登録されるようにします。
今回は記事タイトルを表示したいため、記事タイトルであるlvl1を指定します。

gatsby-config.js
            transformer: ({ data }) =>
              data.allMdx.edges.flatMap(({ node }) => {
                return {
                  id: node.fields.slug,
                  // ...
                  hierarchy: {
                    lvl0: "Blog",
                    lvl1: node.frontmatter.title
                  },
+                  type: "lvl1",
                }
              }),
          },

もう一度サイトをビルドしてインデックスを登録し直すと、ぶじ検索結果の一覧に記事タイトルが表示されるようになりました。

画面キャプチャ:検索結果に記事タイトルが表示されている

検索一覧が表示されるようになったものの、一覧をクリックしても目的のページに遷移しません。
この原因は、urlというプロパティがインデックスにないためでした。
そのため、これまでと同様にgastby-plugin-algoliaの設定でurlプロパティが登録されるようにします。

gatsby-config.js
            transformer: ({ data }) =>
              data.allMdx.edges.flatMap(({ node }) => {
                return {
                  id: node.fields.slug,
                  // ...
                  hierarchy: {
                    lvl0: "Blog",
                    lvl1: node.frontmatter.title
                  },
                  type: "lvl1",
+                  url: `${baseUrl}${node.fields.slug}`
                }
              }),
          },

これで、検索結果から見たいページへ遷移できるようになりました。