{
    "componentChunkName": "component---src-templates-blog-post-jsx",
    "path": "/post/on-site-search-in-gatsby-with-algolia/",
    "result": {"data":{"site":{"siteMetadata":{"title":"WEB EGG","author":"Leko - CTO at Yuimedi"}},"markdownRemark":{"id":"1292e258-745f-506f-9f74-922c6f895ad4","excerpt":"ブログをGatsbyに移行してからずっとサボっていたサイト内検索機能ですが、ゴールデンウィークで時間があったので実装してみました。 なお、当記事はAlgolia自体の知識がある前提で書いてます。 Algolia自体の説明やMiddleman…","html":"<p>ブログをGatsbyに移行してからずっとサボっていたサイト内検索機能ですが、ゴールデンウィークで時間があったので実装してみました。</p>\n<p>なお、当記事はAlgolia自体の知識がある前提で書いてます。<br>\nAlgolia自体の説明やMiddleman製サイトに検索機能を導入する話に関してはこちらの記事をご参照ください。</p>\n<blockquote>\n<p>— <a href=\"/post/implement-site-search-with-algolia/\">Algoliaを利用してMiddleman製サイトに検索機能を実装する | WEB EGG</a></p>\n</blockquote>\n<!--more-->\n<h2 id=\"はじめに\" style=\"position:relative;\"><a href=\"#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB\" aria-label=\"はじめに permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>はじめに</h2>\n<p>当記事はAlgoliaを用いた実現手段の紹介になります。他の手段（JSONファイルに記事データを出力してFuse.js等を用いて全文検索etc）との比較検討などはしていません。<br>\n当記事で使用してる技術に関して、Gatsbyのドキュメントでも紹介されてるのでそちらも併せてご参照ください。</p>\n<blockquote>\n<p>— <a href=\"https://www.gatsbyjs.org/docs/adding-search-with-algolia/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Adding search with Algolia | GatsbyJS</a></p>\n</blockquote>\n<h2 id=\"実装方針\" style=\"position:relative;\"><a href=\"#%E5%AE%9F%E8%A3%85%E6%96%B9%E9%87%9D\" aria-label=\"実装方針 permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>実装方針</h2>\n<p>Middleman時代はフルスクラッチで作っていたのですが、スクラッチだと記事の内容も実装の手間も無駄にかさんでしまうので、楽に導入できるよう今回はAlgolia公式のライブラリを2つ使用します。</p>\n<ol>\n<li>記事をAlgoliaに登録する：<a href=\"https://github.com/algolia/gatsby-plugin-algolia\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">gatsby-plugin-algolia</a></li>\n<li>検索UIを提供する：<a href=\"https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">React InstantSearch</a></li>\n</ol>\n<p>これらを利用することで導入コストをかなり抑えられました。</p>\n<h2 id=\"記事をalgoliaに登録するgatsby-plugin-algolia\" style=\"position:relative;\"><a href=\"#%E8%A8%98%E4%BA%8B%E3%82%92algolia%E3%81%AB%E7%99%BB%E9%8C%B2%E3%81%99%E3%82%8Bgatsby-plugin-algolia\" aria-label=\"記事をalgoliaに登録するgatsby plugin algolia permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>記事をAlgoliaに登録する（gatsby-plugin-algolia）</h2>\n<p>gatsby-plugin-algoliaのリポジトリはこちらです。</p>\n<blockquote>\n<p>— <a href=\"https://github.com/algolia/gatsby-plugin-algolia\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">algolia/gatsby-plugin-algolia: A plugin to push to Algolia based on graphQl queries</a></p>\n</blockquote>\n<p>記事執筆時のREADMEではサイト内のすべてのページを登録するような処理になっていますが、ブログ記事だけを登録したいのでGraphQLのクエリを変えました。</p>\n<p>当サイトでは<a href=\"https://github.com/Leko/WEB-EGG/blob/ca76642dff5e8e64df55e1a92d54881ab105ef05/gatsby-config.js#L153-L199\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">こんな感じ</a>で設定にしてあります。</p>\n<ul>\n<li>query: 記事一覧を取得するGraphQL queryに変更</li>\n<li>transformer: ↑の結果をshallowなオブジェクトの配列に整形</li>\n</ul>\n<p>transformerオプションには「オブジェクトの配列を返す必要がある」「配列の各要素は<code>id</code>という名前のフィールドをもつ必要が有ります」という2点の制約が有ります。<br>\n<code>id</code>フィールドはすべての記事において一意な任意の文字列を指定できます。個人的に自動生成される値ではなくcontrollableな値が好きなのでslugをidにしました。<br>\nそれ以外のフィールドや構造に制約はなく、返却したオブジェクのすべてのフィールドがAlgoliaに登録されます。</p>\n<p>記事の本文を検索対象に含めたい場合、1objectあたりのサイズ制限を突破するために複数のチャンクにちぎって送信するなどの工夫が必要ですが、そもそも本文を検索対象に含めることはAlgoliaが非推奨だと言ってるので本文を含めないように設定しました。</p>\n<blockquote>\n<ol start=\"2\">\n<li>In most cases, having bigger objects is a sign that you’re not using Algolia at its full capacity:\n<ul>\n<li>Having very big chunks of text is usually bad for relevance, because most objects end-up having a lot of similar words, and they will match with a lot of irrelevant queries</li>\n<li>It’s often better to de-duplicate big objects into several smaller ones</li>\n</ul>\n</li>\n</ol>\n<p>— <a href=\"https://www.algolia.com/doc/faq/basics/is-there-a-size-limit-for-my-index-records/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Is there a size limit for my index/records? | Basics FAQ | Docs Algolia</a></p>\n</blockquote>\n<p>設定を済ませて<code>gatsby build</code>を実行すると、記事の一覧がAlgoliaに登録されます。こんな感じ。</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 668px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/0857669880ee0718e32aac6fe49cf485/169e3/records.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 60.47904191616767%; position: relative; bottom: 0; left: 0; background-image: url('data:image/svg+xml,%3csvg%20xmlns=\\'http://www.w3.org/2000/svg\\'%20width=\\'400\\'%20height=\\'242\\'%20viewBox=\\'0%200%20400%20242\\'%20preserveAspectRatio=\\'none\\'%3e%3cpath%20d=\\'M68%2095v9h301V85H68v10m2-8l-1%208v7h299V86H219L70%2087m294%2073c-2%200-2%201-2%204l1%205h5c4%200%205-1%205-4%200-5-3-7-9-5\\'%20fill=\\'%23d3d3d3\\'%20fill-rule=\\'evenodd\\'/%3e%3c/svg%3e'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n          <source\n              srcset=\"/static/0857669880ee0718e32aac6fe49cf485/5251b/records.webp 167w,\n/static/0857669880ee0718e32aac6fe49cf485/7390e/records.webp 334w,\n/static/0857669880ee0718e32aac6fe49cf485/7c056/records.webp 668w,\n/static/0857669880ee0718e32aac6fe49cf485/0a92e/records.webp 1002w,\n/static/0857669880ee0718e32aac6fe49cf485/7fa3c/records.webp 1336w,\n/static/0857669880ee0718e32aac6fe49cf485/9aab7/records.webp 1682w\"\n              sizes=\"(max-width: 668px) 100vw, 668px\"\n              type=\"image/webp\"\n            />\n          <source\n            srcset=\"/static/0857669880ee0718e32aac6fe49cf485/21521/records.png 167w,\n/static/0857669880ee0718e32aac6fe49cf485/86d36/records.png 334w,\n/static/0857669880ee0718e32aac6fe49cf485/74866/records.png 668w,\n/static/0857669880ee0718e32aac6fe49cf485/d69c4/records.png 1002w,\n/static/0857669880ee0718e32aac6fe49cf485/9685e/records.png 1336w,\n/static/0857669880ee0718e32aac6fe49cf485/169e3/records.png 1682w\"\n            sizes=\"(max-width: 668px) 100vw, 668px\"\n            type=\"image/png\"\n          />\n          <img\n            class=\"gatsby-resp-image-image\"\n            src=\"/static/0857669880ee0718e32aac6fe49cf485/74866/records.png\"\n            alt=\"records\"\n            title=\"records\"\n            loading=\"lazy\"\n            decoding=\"async\"\n            style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n          />\n        </picture>\n  </a>\n    </span></p>\n<p>うまく行かない場合、transform関数がオブジェクトの配列を返せているか確認しましょう。</p>\n<h2 id=\"検索uiを提供するreact-instantsearch\" style=\"position:relative;\"><a href=\"#%E6%A4%9C%E7%B4%A2ui%E3%82%92%E6%8F%90%E4%BE%9B%E3%81%99%E3%82%8Breact-instantsearch\" aria-label=\"検索uiを提供するreact instantsearch permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>検索UIを提供する（React InstantSearch）</h2>\n<p>Algoliaに記事を登録して検索できるようになったので、フロントエンドを作ります。<br>\n検索フォームや検索結果の表示にはReact InstantSearchを利用します。</p>\n<h3 id=\"react-instantsearchとは\" style=\"position:relative;\"><a href=\"#react-instantsearch%E3%81%A8%E3%81%AF\" aria-label=\"react instantsearchとは permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>React InstantSearchとは</h3>\n<p><a href=\"https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/js/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">InstantSearch.js</a>というAlgoliaが提供している検索用UI用のコンポーネントのReact版です。<br>\nInstantSearchを利用することで、Algoliaの検索ロジックや状態管理をスクラッチで実装する必要がなくなり、検索UIと検索結果の見た目を作ることだけに注力できます。\n（VueやAngularなどの各種フレームワークやPure JavaScript、webのみならずiOSやAndroid、React Nativeでも使えるように複数バージョンが提供されており、今回はReact版を採用しています）</p>\n<p>公式の<a href=\"https://codesandbox.io/embed/github/algolia/doc-code-samples/tree/master/React+InstantSearch/getting-started\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Live Demo (codesandbox)</a>を見てみると、複雑な検索UIにも対応できるようです。</p>\n<p>React版を使って実装してみて、UIの自由度やカスタマイズ製も高くかなり使いやすかったので採用しました。</p>\n<h3 id=\"動作デモコード\" style=\"position:relative;\"><a href=\"#%E5%8B%95%E4%BD%9C%E3%83%87%E3%83%A2%E3%82%B3%E3%83%BC%E3%83%89\" aria-label=\"動作デモコード permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>動作デモ・コード</h3>\n<p>当サイトの右上にある検索窓が触れるデモです。<br>\n特にチューニングやパラメータの最適化などしていませんが、えげつない速度で検索結果が表示されます。スクショとしてはこんな感じです。</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 668px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/66530b9d897a7d700e5ec4b5121e9fdd/142fb/search-ui.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 85.02994011976048%; position: relative; bottom: 0; left: 0; background-image: url('data:image/svg+xml,%3csvg%20xmlns=\\'http://www.w3.org/2000/svg\\'%20width=\\'400\\'%20height=\\'340\\'%20viewBox=\\'0%200%20400%20340\\'%20preserveAspectRatio=\\'none\\'%3e%3cpath%20d=\\'M33%2094l-1%204c0%202%200%202%203%202s3%200%201%201c-3%200-3%201-3%203s1%203%202%203l1-2%201-2%201%203c0%202%200%202-3%202-4%200-4%203%200%203h4l-3%201c-4%201-4%203%200%202l2%201-2%201-1%201%203%202c1%200%202-1%202-13V93h-3l-4%201M0%20106v11h4c7%200%2011-5%209-12-2-3-5-5-9-4-3%201-3%201-3-3l-1%208m15-3l3%208c3%207%203%207-1%207-4%201-4%204%200%204%205%200%206-2%2010-12%205-10%204-9%202-9s-3%201-4%205l-3%205-2-5c-1-4-2-5-4-5s-2%200-1%202m8%2023c-1%202-1%202-4%202-2-1-3-1-3%201%200%201%201%202%203%202l2%201-3%203c-2%203-3%204-2%205%202%201%202%201%204-1l4-3c3%200%202%201%200%203-7%205-4%2010%206%2010%205%200%206%200%206-2s0-2-5-2c-6%201-8%200-6-3h2l2%202c2%200%202-1%202-3s1-3%204-4%204-3%202-4h-3c-2%202-3%202-6%201-4-2-4-3%200-3s6-1%206-3l-4-1-4-1-1-1c-1-1-2%200-2%201M0%20277v36h19c22%200%2021%200%2021-7v-4h-9c-12%200-19-4-23-12-3-6-2-12%201-18%204-8%208-10%2020-11h11v-11H29l-11-1%201-2c2-4%200-6-10-6H0v36m318%2033v9l1%207h7l8-1v-14c0-3-15-3-16-1\\'%20fill=\\'%23d3d3d3\\'%20fill-rule=\\'evenodd\\'/%3e%3c/svg%3e'); background-size: cover; display: block;\"\n  ></span>\n  <picture>\n          <source\n              srcset=\"/static/66530b9d897a7d700e5ec4b5121e9fdd/5251b/search-ui.webp 167w,\n/static/66530b9d897a7d700e5ec4b5121e9fdd/7390e/search-ui.webp 334w,\n/static/66530b9d897a7d700e5ec4b5121e9fdd/7c056/search-ui.webp 668w,\n/static/66530b9d897a7d700e5ec4b5121e9fdd/468b0/search-ui.webp 907w\"\n              sizes=\"(max-width: 668px) 100vw, 668px\"\n              type=\"image/webp\"\n            />\n          <source\n            srcset=\"/static/66530b9d897a7d700e5ec4b5121e9fdd/21521/search-ui.png 167w,\n/static/66530b9d897a7d700e5ec4b5121e9fdd/86d36/search-ui.png 334w,\n/static/66530b9d897a7d700e5ec4b5121e9fdd/74866/search-ui.png 668w,\n/static/66530b9d897a7d700e5ec4b5121e9fdd/142fb/search-ui.png 907w\"\n            sizes=\"(max-width: 668px) 100vw, 668px\"\n            type=\"image/png\"\n          />\n          <img\n            class=\"gatsby-resp-image-image\"\n            src=\"/static/66530b9d897a7d700e5ec4b5121e9fdd/74866/search-ui.png\"\n            alt=\"search ui\"\n            title=\"search ui\"\n            loading=\"lazy\"\n            decoding=\"async\"\n            style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n          />\n        </picture>\n  </a>\n    </span></p>\n<p>コードは<a href=\"https://github.com/Leko/WEB-EGG/blob/ca76642dff5e8e64df55e1a92d54881ab105ef05/src/components/OnSiteSearch.jsx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">こちら（OnSiteSearchコンポーネント）</a>を読むとInstantSearchコンポーネントとwidgetsの使い方がわかると思います。</p>\n<h3 id=\"react-instantsearchのドキュメント\" style=\"position:relative;\"><a href=\"#react-instantsearch%E3%81%AE%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88\" aria-label=\"react instantsearchのドキュメント permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>React InstantSearchのドキュメント</h3>\n<p><a href=\"https://www.algolia.com/doc/api-reference/widgets/instantsearch/react/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">https://www.algolia.com/doc/api-reference/widgets/instantsearch/react/</a></p>\n<p>これを読みつつお好みでウィジェットを足していく感じになると思います。<br>\n基本的にドキュメント見ながらやるだけなんですが、実装してて思った注意事項を以下に残します。</p>\n<h3 id=\"フロントエンドへ環境変数を渡したい\" style=\"position:relative;\"><a href=\"#%E3%83%95%E3%83%AD%E3%83%B3%E3%83%88%E3%82%A8%E3%83%B3%E3%83%89%E3%81%B8%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%82%92%E6%B8%A1%E3%81%97%E3%81%9F%E3%81%84\" aria-label=\"フロントエンドへ環境変数を渡したい permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>フロントエンドへ環境変数を渡したい</h3>\n<p>ローカルと本番環境で検索対象のインデックスを分けるためにAPI KEYなどを環境変数に逃がしたくなると思います。<br>\nGatsbyにはwebpackのDefinePluginが入っているので、ちょっと設定をしてあげれば各設定値を環境変数に逃がせます。</p>\n<blockquote>\n<p>— <a href=\"https://www.gatsbyjs.org/docs/environment-variables/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Environment Variables | GatsbyJS</a></p>\n<p>— <a href=\"https://qiita.com/github0013@github/items/f138ce14a69ca8bfd068\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">gatsby Environment Variables まとめ - Qiita</a></p>\n</blockquote>\n<h3 id=\"未入力のときは検索結果を表示したくない\" style=\"position:relative;\"><a href=\"#%E6%9C%AA%E5%85%A5%E5%8A%9B%E3%81%AE%E3%81%A8%E3%81%8D%E3%81%AF%E6%A4%9C%E7%B4%A2%E7%B5%90%E6%9E%9C%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%9F%E3%81%8F%E3%81%AA%E3%81%84\" aria-label=\"未入力のときは検索結果を表示したくない permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>未入力のときは検索結果を表示したくない</h3>\n<p>デフォルトのウィジェットだけで検索UIを組むと、何も入力してない状態でも検索結果が表示されていると思います。<br>\nサイト内検索では何か入力したときだけ結果を表示するためカスタマイズしました。</p>\n<p><code>connectStateResults</code>というHoCがexportされているので、それを利用してStateに対する見た目を制御できます。詳しくはドキュメント参照。<br>\nなお、こちらのドキュメントに検索結果が空の場合、エラーハンドリングについても記載が有ります。</p>\n<blockquote>\n<p>— <a href=\"https://www.algolia.com/doc/guides/building-search-ui/going-further/conditional-display/react/\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Conditional display | Building Search UI | Guide | Algolia Documentation</a></p>\n</blockquote>\n<h3 id=\"algoliaのロゴを表示したい\" style=\"position:relative;\"><a href=\"#algolia%E3%81%AE%E3%83%AD%E3%82%B4%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%97%E3%81%9F%E3%81%84\" aria-label=\"algoliaのロゴを表示したい permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Algoliaのロゴを表示したい</h3>\n<p><a href=\"https://github.com/Leko/WEB-EGG/blob/ca76642dff5e8e64df55e1a92d54881ab105ef05/src/components/OnSiteSearchHitList.jsx\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">こちら（OnSiteSearchHitListコンポーネント）</a>のように実装しました。<br>\nInstantSearchの<code>Panel</code>コンポーネントを利用してヘッダとフッタを作り、フッタに<code>PoweredBy</code>コンポーネントを表示してCSSでちょっと見た目を調整しました。<br>\nCSSに関しては<a href=\"https://github.com/Leko/WEB-EGG/blob/ca76642dff5e8e64df55e1a92d54881ab105ef05/src/styles/OnSiteSearch.css#L44-L51\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">こちら</a>をご参照ください。</p>\n<h2 id=\"さいごに\" style=\"position:relative;\"><a href=\"#%E3%81%95%E3%81%84%E3%81%94%E3%81%AB\" aria-label=\"さいごに permalink\" class=\"autolink-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>さいごに</h2>\n<p>Gatsby製サイトに検索機能を追加するときの参考になれば幸いです。</p>\n<p>スクラッチで作るよりはるかに簡単に導入できた（デバッグ含めて3hくらい）ので、Gatsbyのようにエコシステムが充実しているものに乗っかるのは正義だなと思いました。</p>","timeToRead":9,"frontmatter":{"title":"Gatsby製サイトにAlgoliaのサイト内検索を実装する","tags":["Algolia","JavaScript","Node.js","Gatsby","React"],"date":"May 06, 2019","featuredImage":{"childImageSharp":{"fluid":{"tracedSVG":"data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='400'%20height='130'%20viewBox='0%200%20400%20130'%20preserveAspectRatio='none'%3e%3cpath%20d='M0%2060v35h13l23-1c12%200%2014-1%2011-5-1-2%200-2%2050-2a1654%201654%200%200096-4c0-4-1-4-56-5l-57-1c-16-4-17-26-3-33%204-2%208-2%2063-2a603%20603%200%200023-2c-27%200-31%200-30-1l1-4c-1-2-2-2-29-2H77l1-3-1-4-39-1H0v35m258-6c-2%204%204%2010%207%208s5-6%204-8c-1-3-10-3-11%200m76%205l-2%208-2%204h9c8%200%208%200%209-3l-1-3c-1-2%200-2%209-2h11v-6l-17-1h-16v3'%20fill='%23d3d3d3'%20fill-rule='evenodd'/%3e%3c/svg%3e","aspectRatio":3.0925925925925926,"src":"/static/805aa3b7b4b5304126127d01dcd71951/8eab8/featured-image.png","srcSet":"/static/805aa3b7b4b5304126127d01dcd71951/1ec58/featured-image.png 334w,\n/static/805aa3b7b4b5304126127d01dcd71951/ccb4a/featured-image.png 668w,\n/static/805aa3b7b4b5304126127d01dcd71951/8eab8/featured-image.png 1336w,\n/static/805aa3b7b4b5304126127d01dcd71951/85e22/featured-image.png 2004w,\n/static/805aa3b7b4b5304126127d01dcd71951/a9ec1/featured-image.png 2672w,\n/static/805aa3b7b4b5304126127d01dcd71951/b3888/featured-image.png 2878w","srcWebp":"/static/805aa3b7b4b5304126127d01dcd71951/f7e47/featured-image.webp","srcSetWebp":"/static/805aa3b7b4b5304126127d01dcd71951/cd98f/featured-image.webp 334w,\n/static/805aa3b7b4b5304126127d01dcd71951/7535d/featured-image.webp 668w,\n/static/805aa3b7b4b5304126127d01dcd71951/f7e47/featured-image.webp 1336w,\n/static/805aa3b7b4b5304126127d01dcd71951/f6b67/featured-image.webp 2004w,\n/static/805aa3b7b4b5304126127d01dcd71951/f71bf/featured-image.webp 2672w,\n/static/805aa3b7b4b5304126127d01dcd71951/650fc/featured-image.webp 2878w","sizes":"(max-width: 1336px) 100vw, 1336px"}}}}}},"pageContext":{"slug":"/on-site-search-in-gatsby-with-algolia/","previous":{"fields":{"slug":"/what-benefit-of-intl-number-format/"},"frontmatter":{"title":"Intl.NumberFormatでゼロ埋めや％表記などの数値表現を楽に実装する","tags":["JavaScript","Node.js"]}},"next":{"fields":{"slug":"/dynamic-import-tips-for-gatsby/"},"frontmatter":{"title":"GatsbyでReactコンポーネントをDynamic importしてCode Splitするwork around","tags":["JavaScript","Gatsby","React"]}}}},
    "staticQueryHashes": ["2585454260","2954598359"]}