華麗なるGatsby.jsの実践(styled-components/headの編集/404ページ/画像の使用)

以前 [gatsbyの公式チュートリアルを意訳しつつやった](https://qiita.com/irico/items/cf87eb29ecaf7e135fcd)ので、今回は、実際に業務で使用するにあたって
使いそうな機能について公式のドキュメント等を調べてみました。

![スクリーンショット 2020-05-15 14.10.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441432/a350ec47-4d0c-0c61-7162-2bb7277641e1.png)

この記事のタイトルをつけた後に気づいたんですが、
[公式](https://www.gatsbyjs.org/docs/gatsby-image/#fluid-images)で上記の画像を発見しました。
華麗なるギャツビーがやはり由来なんでしょうか。


## お品書き
実際業務で使いそうな機能をピックアップしたところ、以下のようになりました。
- styled-componentsを使いたい
- head修正できるようにしたい
- 404ページをカスタマイズしたい
- gatsbyでの画像の扱いを知りたい

今回はhttps://www.gatsbyjs.org/starters/gatsbyjs/gatsby-starter-default/
このスターターを使って進めます。

スターターを使用するために、以下のコマンドを実行します。

```
$ gatsby new app https://github.com/gatsbyjs/gatsby-starter-default
$ cd app
$ gatsby develop
```


## styled-componentsを使いたい
[公式参考ページはこちら](https://www.gatsbyjs.org/docs/styled-components/)

必要なプラグインを取得します。

```
$ npm install --save gatsby-plugin-styled-components styled-components babel-plugin-styled-components
```



babel-plugin-styled-componentsはstyled-componentsをより扱いやすくしてくれるpluginです。

https://github.com/styled-components/babel-plugin-styled-components



gatsby-config.jsに以下を書き加えます。

```js:gatsby-config.js
module.exports = {
  plugins: [`gatsby-plugin-styled-components`],
}
```



あとは使うだけ。思ったよりも簡単だった。



```react:index.html
import styled from "styled-components"


const IndexPage = () => (
  <div>
    <Title>宇宙の日記</Title>
  </div>
)

export default IndexPage

const Title = styled.h1`
  color: blue;
`
```

## head修正できるようにしたい
[公式の参考ページはこちら](https://www.gatsbyjs.org/docs/add-page-metadata/)
実は上記スターターにはすでに組み込まれていますが、念の為最初から実装方法を確認します。



gatsbyではreact helmetがサポートされているのでそれを使う。

```
npm install --save gatsby-plugin-react-helmet react-helmet
```



gatsby-config.jsに下記２つをを加える。

```js:gatsby-config.js
{
  plugins: [`gatsby-plugin-react-helmet`]
}
```

```js:gatsby-config.js
module.exports = {
  siteMetadata: {
    title: `色々な紙飛行機`,
    description: `多種多様な紙飛行機。その世界に触れてみませんか？`,
    author: `@irico`,
  },
```



下記のようなcomponentを準備して...



```react:src/components/SEO
import React from "react"
import { Helmet } from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"

function SEO() {
  const { site } = useStaticQuery(
    graphql`
      query {
        site {
          siteMetadata {
            title
            description
          }
        }
      }
    `
  )

  return (
    <Helmet
      title={site.siteMetadata.title}
      meta={[
        {
          name: `description`,
          content: site.siteMetadata.description,
        },
      ]}
    />
  )
}

export default SEO
```



あとはpageで使うだけ!これも簡単。
ページごとにカスタマイズしたいのであれば、SEOのpropsとして渡して分岐させてあげればよし。

```react
const IndexPage = () => {
		<Layout>
			<SEO />
			...
		</Layout>
}
```

## 404ページをカスタマイズしたい
[公式の参考ページはこちら](https://www.gatsbyjs.org/docs/add-404-page/)



```
^\/?404\/?$ (/404/, /404, 404/ or 404)
```

上記の正規表現に該当するpageを作成すればいいだけ!

`gatsby develop`コマンドでは下記の画像のようなページになりますが、 ビルド後はカスタマイズした404ページに飛ぶようになります。

実はこれも上記スターターで最初からページが用意されています（至れり尽くせり)

ローカルで404ページを確認したいときは、 **Preview custom 404 page**を閲覧すればOK！
![スクリーンショット 2020-05-13 18.19.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/441432/2efd0371-0ca5-b97d-3199-16e2a161b6ec.png)

## gatsbyでの画像の扱いを知りたい
[公式の参考サイトはこちら](https://www.gatsbyjs.org/docs/images-and-files/)
普通のパス指定での読み方ももちろんできるが、webpackによるimportがオススメです。
ファイルをあたかもJSソースのように取得することができ、以下の恩恵が得られます。

- webpackが圧縮をおこなってくれる
- ユーザーに404エラーを出す前にコンパイルエラーが出る（チェック漏れを防ぐ)
- ファイル名にハッシュが含まれるおかげで、ブラウザのキャッシュを防ぐ。



```react
import kvImg from "../images/kv.jpg"

const IndexPage = () => (
  <Layout>
    <IndexWrapper>
       <img src={kvImg} alt="紙飛行機の画像" />
    </IndexWrapper>
  </Layout>
)
```



**escape hatch**あるよ!

アプリ下に`static`というファイルを作ってこのファイル内に画像などを置くと、`public`フォルダー内にコピーされる。
そうすると呼び出さずに画像を使うことができる!

staticフォルダーにkv.jpgを配置したのち、

```react
const IndexPage = () => (
  <Layout>
    <IndexWrapper>
       <img src='/kv.jpg' alt="紙飛行機の画像" />
    </IndexWrapper>
  </Layout>
)
```

勝手にコピーしてくれるので呼び出しは不要!

ただ、以下の短所がある。

- ファイルが縮小されない
- ユーザー側に404が表示される
- コンテンツハッシュが含まれないため、キャッシュされてしまう



なので基本的にはJSを介してアセットを使うのがいいです。static folderが役に立つのは以下のような場合になります。

- maifestなどの、特定のファイル名でなければならないもの

- 画像がたくさんあり、パスを動的に参照する必要がある場合

- Pace.jsのように、バンドルするコード外部に小規模のスクリプトを読み込みたい場合

- webpackと互換性がないもの

  etc..



### gatsby-image

https://www.gatsbyjs.org/tutorial/gatsby-image-tutorial/#querying-data-for-a-single-image

- Intersection Observer APIを使用した遅延読み込み
- 画像の位置を保持することで、画像を読んだ途端ページ位置がずれることを防ぐ
- 灰色の背景/ぼやけた画像などの設定が簡単にできる。

などなど、モダンな画像処理をしてくれるらしいです。

ただし、 imgタグの完璧な代替ではないので注意。適したものとしては、固定された大きさのイメージやコンテナ全体に大きく広がるイメージなど。

実は上記スターターでは、宇宙飛行士の絵でgatsby-imageが使用されています。(src/component/image.js)

```
npm install gatsby-transformer-sharp gatsby-plugin-sharp gatsby-image
```

どのスターターも用いてない場合は、下記もインストールする。スターターを使用している場合は最初から含まれているパッケージです。

```
npm install gatsby-source-filesystem
```



gatsby-config.jsを下記のように書き直す。

```js
module.exports = {
  plugins: [
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/data/`,
      },
    },
  ],
}
```

GraphQLで画像データを扱えるようにするために,gatsby-sourcr-filesystemに画像があるフォルダーを教えています。



先にsrc/components/image.js設定部分を示します。

```react
import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Img from "gatsby-image"

const Image = () => {
  const data = useStaticQuery(graphql`
    query {
      placeholderImage: file(relativePath: { eq: "gatsby-astronaut.png" }) {
        childImageSharp {
          fluid(maxWidth: 300) {
            ...GatsbyImageSharpFluid
          }
        }
      }
    }
  `)

  return <Img fluid={data.placeholderImage.childImageSharp.fluid} />
}

export default Image
```

fileのパスは、先ほどgatsby-source-filesystemのconfigで設定したパスからの相対パスとなります。

まず知るべきなのは、gatsby-imageでは２つのresponsiveタイプがあるということです。

- fixed

- fluid

  fixedは固定幅,fluidはコンテナに合わせて縮小拡大するタイプです。

上記のクエリを用いてサイズを指定します。



[GraphQL fragments](https://www.gatsbyjs.org/packages/gatsby-image/#fragments)  を使うことでイメージの設定を行うことができます。
`GatsbyImageSharpFluid`もそのフラグメントの１つ。
ただしこれは、GraphiQLでは使用できないので注意。

フラグメントについてはいまいち使い分け等がわからなかったので今後要調査....。

画像等の扱いについては上記4つの方法がありますが、使い分けについては

- 直接パス指定 ・・・あまり使わなそう
- gatsby-image　・・・基本的にはこれ！最適化等してくれるので楽
- jsでのimport ・・・imgタグで色々カスタマイズして配置したい場合
- static folder ・・・動的な読み込みや制約がある等

と感じました。実際に使っていく中で適宜使い分けたいと思います。


## 所感
実務で必要そうだな...と思った部分はほとんどスターターに最初から組み込まれていました。
しかも、使用したい機能についてはドキュメントが手厚く説明してくれてることが多かったです。
優秀ですね!
次回はwordpress等のプラグインやフォーム等がどこまで使えるのか？について調べてみたいと思います。
静的サイトジェネレータなので、動的な部分はほどほどがいいのかもしれませんが、その辺のパフォーマンス的な兼ね合いも調査しつつ...