GatsbyなWebサイトに検索機能を追加してみる

Twitterで見かけた、Add Super Fast Search in Your Gatsby Website (Ultimate Guide for Adding Algolia’s Search to Gatsby Website) を試してみたいと思います 🙂

Gatsyでブログサイトを作る

とりあえず gatsby-starter-blog に沿ってGatsbyなブログサイトを作ってみます。

↓叩いてみたら、、

npx gatsby new my-blog-starter https://github.com/gatsbyjs/gatsby-starter-blog
info Creating new site from git: https://github.com/gatsbyjs/gatsby-starter-blog.git
Cloning into 'my-blog-starter'...
remote: Enumerating objects: 1348, done.
remote: Total 1348 (delta 0), reused 0 (delta 0), pack-reused 1348
Receiving objects: 100% (1348/1348), 2.93 MiB | 1.75 MiB/s, done.
Resolving deltas: 100% (745/745), done.
success Created starter directory layout
info Installing packages...
yarn install v1.3.2
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning " > eslint-plugin-react@7.11.1" has unmet peer dependency "eslint@^3.0.0 || ^4.0.0 || ^5.0.0".
warning "gatsby > mini-css-extract-plugin > schema-utils > ajv-errors@1.0.1" has unmet peer dependency "ajv@>=5.0.0".
[4/4] 📃  Building fresh packages...
[-/5] ⠠ waiting...
[2/5] ⠠ sharp: gyp
[-/5] ⠠ waiting...
[-/5] ⠠ waiting...

↓エラー吐いて落ちてる…w メッセージ的にはPython2がありませんってことみたいですね、、

Exit code: 1
Command: (node install/libvips && node install/dll-copy && prebuild-install) || (node-gyp rebuild && node install/dll-copy)
Arguments: 
Directory: /Users/eshinoha/my-blog-starter/node_modules/sharp
Output:
info sharp Downloading https://github.com/lovell/sharp-libvips/releases/download/v8.7.0/libvips-8.7.0-darwin-x64.tar.gz
prebuild-install WARN install No prebuilt binaries found (target=9.10.1 runtime=node arch=x64 platform=darwin)
gyp info it worked if it ends with ok
gyp info using node-gyp@3.8.0
gyp info using node@9.10.1 | darwin | x64
gyp ERR! configure error 
gyp ERR! stack Error: Command failed: /Users/eshinoha/.pyenv/shims/python2 -c import sys; print "%s.%s.%s" % sys.version_info[:3];
gyp ERR! stack pyenv: python2: command not found
gyp ERR! stack 
gyp ERR! stack The `python2' command exists in these Python versions:
gyp ERR! stack   anaconda3-4.3.1/envs/py27
gyp ERR! stack 
gyp ERR! stack 
gyp ERR! stack     at ChildProcess.exithandler (child_process.js:273:12)
gyp ERR! stack     at ChildProcess.emit (events.js:180:13)
gyp ERR! stack     at maybeClose (internal/child_process.js:936:16)
gyp ERR! stack     at Socket.stream.socket.on (internal/child_process.js:353:11)
gyp ERR! stack     at Socket.emit (events.js:180:13)
gyp ERR! stack     at Pipe._handle.close [as _onclose] (net.js:541:12)
gyp ERR! System Darwin 17.7.0
gyp ERR! command "/usr/local/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /Users/eshinoha/my-blog-starter/node_modules/sharp

手元のPythonのバージョン見てみると3.6ですよ、と。

$ python --version
Python 3.6.0 :: Anaconda 4.3.1 (x86_64)

py27っていうそれっぽいの入ってるっぽいので、そっちにしてみる

a$ conda info --envs
# conda environments:
#
py27                     /Users/eshinoha/.pyenv/versions/anaconda3-4.3.1/envs/py27
root                  *  /Users/eshinoha/.pyenv/versions/anaconda3-4.3.1

$ source /Users/eshinoha/.pyenv/versions/anaconda3-4.3.1/envs/py27/bin/activate py27

もっかいコマンド流したら、そのディレクトリ既にあるよ、と。ですよねぇw

$ npx gatsby new my-blog-starter https://github.com/gatsbyjs/gatsby-starter-blog
error Directory my-blog-starter is already an npm project

上手くいったようです 🙂

$ npx gatsby new my-blog-starter https://github.com/gatsbyjs/gatsby-starter-blog
info Creating new site from git: https://github.com/gatsbyjs/gatsby-starter-blog.git
Cloning into 'my-blog-starter'...
remote: Enumerating objects: 1348, done.
remote: Total 1348 (delta 0), reused 0 (delta 0), pack-reused 1348
Receiving objects: 100% (1348/1348), 2.93 MiB | 1.69 MiB/s, done.
Resolving deltas: 100% (745/745), done.
success Created starter directory layout
info Installing packages...
yarn install v1.3.2
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning " > eslint-plugin-react@7.11.1" has unmet peer dependency "eslint@^3.0.0 || ^4.0.0 || ^5.0.0".
warning "gatsby > mini-css-extract-plugin > schema-utils > ajv-errors@1.0.1" has unmet peer dependency "ajv@>=5.0.0".
[4/4] 📃  Building fresh packages...
✨  Done in 62.48s.

gatsby-cliをインストールして(npmよくわかってなくて–globalで入れないと動かなかったんだけど、そういうもの?)

$ npm install --global gatsby-cli
/usr/local/bin/gatsby -> /usr/local/lib/node_modules/gatsby-cli/lib/index.js
+ gatsby-cli@2.4.8
added 211 packages from 119 contributors in 10.024s

んで、gatsby develop叩いたら、メッチャ 『error Plugin gatsby-plugin-xxx returned an error』的なエラーが出てて、localhost:8000も↓こんな感じ(http://localhost:8000/___graphql はGraphQLのエディタが立ち上がってくるけど…)

Screen Shot 2019-01-24 at 17.17.05

ディレクトリごと消して、もっかいnpxからやり直したら↓上手くいった…w まぁイイ、先進みます!

$ gatsby develop
success open and validate gatsby-configs — 0.109 s
success load plugins — 0.419 s
success onPreInit — 11.370 s
success delete html and css files from previous builds — 0.006 s
success initialize cache — 0.019 s
success copy gatsby files — 0.080 s
success onPreBootstrap — 0.006 s
success source and transform nodes — 0.240 s
success building schema — 0.488 s
success createPages — 0.101 s
success createPagesStatefully — 0.070 s
success onPreExtractQueries — 0.006 s
success update schema — 0.354 s
success extract queries from components — 0.256 s
Generating image thumbnails [==============================] 4/4 0.0 secs 100%
success run graphql queries — 0.982 s — 9/9 9.20 queries/second
success write out page data — 0.009 s
success write out redirect data — 0.001 s
Generating image thumbnails [==============================] 11/11 0.8 secs 100%
Generating image thumbnails [==============================] 18/18 1.2 secs 100%

info bootstrap finished - 18.677 s

⢀ onPostBootstrapdone generating icons for manifest
success onPostBootstrap — 0.276 s
 DONE  Compiled successfully in 4312ms                                                                                                                                      17:23:12


You can now view gatsby-starter-blog in the browser.

  http://localhost:8000/

View GraphiQL, an in-browser IDE, to explore your site's data and schema

  http://localhost:8000/___graphql

Note that the development build is not optimized.
To create a production build, use gatsby build

ℹ 「wdm」: 
ℹ 「wdm」: Compiled successfully.

とにかく画面出たしね 🙂

Screen Shot 2019-01-24 at 17.24.42

ということでようやく本題

流れ的には以下のような感じ。

  1. Algoliaのセットアップ
  2. GatsbyのビルドスクリプトにAlgoliaへのコンテンツアップロードを追加
  3. Algoliaを利用した検索UIの追加
  4. GatsbyのStarterブログの流れに沿っている、とのこと。

Algoliaのセットアップ

Screen Shot 2019-01-24 at 11.23.06
https://www.algolia.com/

posts というインデックスを作りました

Screen Shot 2019-01-24 at 11.25.24

API Keysメニューから以下の情報を取得

API_Keys___Algolia

Algoliaへのインデクシング

yarnでdotenvという環境変数的なアレと、gatsby-plugin-algoliaというそれっぽいプラグインをインストールします。なんかwarning出てるっぽいけど、とりあえず入りました。

$ yarn add dotenv gatsby-plugin-algolia
yarn add v1.3.2
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning " > eslint-plugin-react@7.11.1" has unmet peer dependency "eslint@^3.0.0 || ^4.0.0 || ^5.0.0".
warning "gatsby > mini-css-extract-plugin > schema-utils > ajv-errors@1.0.1" has unmet peer dependency "ajv@>=5.0.0".
[4/4] 📃  Building fresh packages...
success Saved lockfile.
success Saved 13 new dependencies.
├─ agentkeepalive@2.2.0
├─ algoliasearch@3.32.0
├─ death@1.1.0
├─ dotenv@6.2.0
├─ envify@4.1.0
├─ es6-promise@4.2.5
├─ foreach@2.0.5
├─ gatsby-cli@1.1.58
├─ gatsby-plugin-algolia@0.3.0
├─ load-script@1.0.0
├─ lodash.chunk@4.2.0
├─ reduce@1.0.1
└─ yurnalist@0.2.1
✨  Done in 36.69s.

.env に上記でAlgoliaのダッシュボードから取得した文字列を↓のxxx,yyy,zzzのところにセットします。特にAdminのkeyとかGitHub載せちゃうと、やりたい放題されてされてしまう可能性があるので、.envは.gitignoreでお願いします的な。

GATSBY_ALGOLIA_APP_ID=xxx
GATSBY_ALGOLIA_ADMIN_API_KEY=yyy
GATSBY_ALGOLIA_SEARCH_API_KEY=zzz
GATSBY_ALGOLIA_INDEX_NAME=posts

次に gatsby-config.js を編集して、プラグインの設定のところで、gatsby-plugin-algoliaにはgatsby-plugin-algolia-config.jsをロードしてね的な↓を追加してあげます。

module.exports = {
  plugins: [
    //...
    {
      resolve: `gatsby-plugin-algolia`,
      options: require(`./gatsby-plugin-algolia-config.js`),
    },
    //...
  ],
}

で、その gatsby-plugin-algolia-config.js は↓こんな感じで。dotenvから読み込んだ値を使ってGraphQLゴニョゴニョ的な。

require('dotenv').config({
  path: `.env`,
})

const queries = [
  {
    query: `
      {
        allMarkdownRemark {
          edges {
            node {
              excerpt
              frontmatter {
                title
              }
              fields {
                slug
              }
            }
          }
        }
      }
    `,
    transformer: ({ data }) =>
      data.allMarkdownRemark.edges.map(
        ({
          node: {
            excerpt,
            frontmatter: { title },
            fields: { slug },
          },
        }) => ({
          title,
          description: excerpt,
          path: slug,
        })
      ),
  },
]

module.exports = {
  appId: process.env.GATSBY_ALGOLIA_APP_ID,
  apiKey: process.env.GATSBY_ALGOLIA_ADMIN_API_KEY,
  indexName: process.env.GATSBY_ALGOLIA_INDEX_NAME,
  queries,
}

で、gatsby buildしてあげます。成功したっぽい。

$ gatsby build
success open and validate gatsby-configs — 0.012 s
success load plugins — 0.335 s
success onPreInit — 2.522 s
success delete html and css files from previous builds — 0.012 s
info One or more of your plugins have changed since the last time you ran Gatsby. As
a precaution, we're deleting your site's cache to ensure there's not any stale
data
success initialize cache — 0.019 s
success copy gatsby files — 0.075 s
success onPreBootstrap — 0.005 s
success source and transform nodes — 0.106 s
success building schema — 0.411 s
success createPages — 0.061 s
success createPagesStatefully — 0.034 s
success onPreExtractQueries — 0.006 s
success update schema — 0.213 s
success extract queries from components — 0.151 s
success run graphql queries — 0.274 s — 9/9 33.12 queries/second
success write out page data — 0.006 s
success write out redirect data — 0.001 s
⢀ onPostBootstrapdone generating icons for manifest
success onPostBootstrap — 0.310 s

info bootstrap finished - 8.485 s

success Building production JavaScript and CSS bundles — 8.564 s
success Building static HTML for pages — 0.862 s — 7/7 25.64 pages/second
⠁ Algolia: 1 queries to index
⠄ index to AlgoliaAlgolia: query 0: executing query
Algolia: query 0: splitting in 1 jobs
success index to Algolia — 1.829 s
Generated public/sw.js, which will precache 10 files, totaling 273875 bytes.
info Done building in 19.866 sec

Algoliaのダッシュボードにもデータが入っていました 🙂

Screen Shot 2019-01-24 at 18.36.52

検索用のUI

ようやくそれっぽいところに差し掛かってきました。今回は autocomplete.js を使います。

まずは Layout.js を開いて、Searchbox をインポートします。src/components/Layout.js を開いて↓を追加。

import SearchBox from './SearchBox'
〜略〜
    return (
      <div
        style={{
          marginLeft: `auto`,
          marginRight: `auto`,
          maxWidth: rhythm(24),
          padding: `${rhythm(1.5)} ${rhythm(3 / 4)}`,
        }}
      >
        <SearchBox /> // んま、こんなに上じゃなくてもイイかもw
        {header}

次に SearchBox.js ファイルを作成。このコードはちゃんと読んでおきたいけど、とりあえずコピペ。

import React, { Component } from 'react'
import { navigate } from 'gatsby'
import './SearchBox.css'

let algoliasearch, autocomplete, client, index

if (typeof window !== 'undefined') {
  algoliasearch = require('algoliasearch/lite')
  autocomplete = require('autocomplete.js')
  client = algoliasearch(
    process.env.GATSBY_ALGOLIA_APP_ID,
    process.env.GATSBY_ALGOLIA_SEARCH_API_KEY
  )
  index = client.initIndex(process.env.GATSBY_ALGOLIA_INDEX_NAME)
}

class SearchBox extends Component {
  componentDidMount() {
    if (typeof window === 'undefined') {
      return
    }
    autocomplete('#algolia-search-input', { hint: false }, [
      {
        source: autocomplete.sources.hits(index, { hitsPerPage: 5 }),
        displayKey: 'title',
        templates: {
          suggestion: function({ _highlightResult: { title, description } }) {
            return `
                <p class="title">${title.value}</p>
                <p class="description">${description.value}</p>
                `
          },
          footer:
            '<div class="branding">Powered by <img src="https://www.algolia.com/static_assets/images/press/downloads/algolia-logo-light.svg" /></div>',
        },
      },
    ]).on('autocomplete:selected', function(
      event,
      suggestion,
      dataset,
      context
    ) {
      navigate(suggestion.url)
    })
  }
  render() {
    return (
      <div style={{ marginBottom: '1rem' }}>
        <input
          type="search"
          id="algolia-search-input"
          placeholder="Search"
          style={{
            border: 'none',
          }}
        />
      </div>
    )
  }
}

export default SearchBox

↑のjsが呼んでるcssであるSearchBox.cssを同じディレクトリに配置。

で、最後にyarnで algoliasearch と autocomplete.js を追加。

$ yarn add algoliasearch autocomplete.js
yarn add v1.3.2
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
warning Pattern ["algoliasearch@^3.32.0"] is trying to unpack in the same destination "/Users/eshinoha/Library/Caches/Yarn/v1/npm-algoliasearch-3.32.0-5818168c26ff921bd0346a919071bac928b747ce" as pattern ["algoliasearch@^3.24.5"]. This could result in a non deterministic behavior, skipping.
[3/4] 🔗  Linking dependencies...
warning " > eslint-plugin-react@7.11.1" has unmet peer dependency "eslint@^3.0.0 || ^4.0.0 || ^5.0.0".
warning "gatsby > mini-css-extract-plugin > schema-utils > ajv-errors@1.0.1" has unmet peer dependency "ajv@>=5.0.0".
[4/4] 📃  Building fresh packages...
success Saved lockfile.
success Saved 3 new dependencies.
├─ algoliasearch@3.32.0
├─ autocomplete.js@0.35.0
└─ immediate@3.2.3
✨  Done in 6.66s.

そんなこんなで↓検索窓が設置されました 🙂

Screen Shot 2019-01-24 at 19.06.24

シェアする

  • このエントリーをはてなブックマークに追加

フォローする