Gatsby.js ページの追加・共通設定する方法を学ぶ

# はじめに
- [こちらの記事](https://qiita.com/marumeru/items/fa7c804d634f60bed0ce)の続きです。
- [gatsby-starter-hello-world](https://github.com/gatsbyjs/gatsby-starter-hello-world)のスターターを使ってプロジェクトを作成した状態から開始になります。
- 以下の操作は全てDokcerコンテナ上で行っています。

# ゴール
Gatsby.jsでページの追加・共通設定する方法を学ぶ
- ページを追加して、ページ間を遷移できるようにする
- 全ページに共通なCSSやレイアウトを作成して適用する
- 404エラーのページを作成する
- headタグを設定する

# 参考
https://zenn.dev/tomokiya/books/4b13342f6d878b93e06c/viewer/aad1360798a7673ffe02

# ページ作成
Gatsby.jsでは`src/pages`にファイルを作成すると、`localhost:8000/ファイル名`のURLで新しいページが作成される


### 手順

1. `src/pages`に任意のJSを作成する

    ``` bash
        ├── src
        │   └── pages
        │       ├── index.js
        │       └── page2.js ←作成する
    ```
    
    ```react:page2.js
    import React from "react";
    
    export default function Page2() {
        return <div>Page2です</div>;
    }
    ```

### 【確認】
作成したページにアクセスする
`localhost:8000/page2`にアクセスすると作成したページが表示できる

 <img width="400" alt="page2を表示した時の画像" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/a551234b-78c1-d3aa-5c73-63ed5f97393a.png">

:::note info
`gatsby develop`中にファイルを作成してもwatchされているので、再起動せずに作成したページにアクセスできる
:::


# 画面遷移
Gatsby.jsではリンクを作るための`<Link>`コンポーネントが提供されていて、これを使うことでページの遷移が手軽に実装できる

### 手順
1. 各ページに`<Link>`を追加する
    `to=""`には遷移先のパスを記載する

    ```react:index.js
    import React from "react";
    import {Link} from "gatsby";
    
    export default function Home() {
    
      return (
        <>
            <div>Hello world!</div>
            <Link to="/page2">別のページへ</Link>
        </>
      );
    }
    ```

    ```react:page2.js
    import React from "react";
    import { Link } from "gatsby";
    
    export default function Page2() {
        return (
            <>
                <div>Page2です</div>
                <Link to="/">ホームに戻る</Link> 
            </>
        );
    }
    ```

### 【確認】
ページのリンクをクリックするとそれぞれのページに遷移できる
<img width="400" alt="index.jsを表示した時の画像" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/d33ca2d2-77e3-cb0b-1b15-f5f2c8ceb6ce.png">
<img width="400" alt="page2を表示した時の画像" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/9a6213dc-1945-fd80-3908-70588d830bb0.png">


# ページ全体にCSSを適用させる
プロジェクトディレクトリ直下に`gatsby-browser.js`を作成し、このファイル内でcssをimportすることでページ全体にCSSを適用させることができる
(`gatsby-browser.js`については[こちらの記事](https://qiita.com/marumeru/items/fa7c804d634f60bed0ce)に簡単にまとめています)

公式はCSSの作成場所は`static`フォルダをすすめている？

https://www.gatsbyjs.com/docs/how-to/images-and-media/static-folder/


### 手順

```
. my-gatsby-site
    ├── gatsby-browser.js ←追加する
    ├── gatsby-config.js
    ├── 〜略〜
    ├── src
    └── static
        ├── styles        ←追加する
        │   └── style.css ←追加する
        └── favicon.ico
```

1. グローバル CSS ファイルを作成する

    ```style.css
    body {
        background-color: pink;
    }
    ```

1. `gatsby-browser.js` を作成して、作成したCSS ファイルを読み込ませる 

    ```react:gatsby-browser.js
    import "/static/styles/style.css"
    ```

1. 開発サーバーが動いていたら再起動する
    `gatsby-browser.js`はビルド時に読み込まれるので、開発サーバーが動いていたら再起動する

### 【確認】
全てのページにCSSが適用された
<img width="400" alt="indexページのイメージ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/a3f973ee-048e-0ebe-28a5-202cfb8c3484.png" />

<img width="400" alt="page2のイメージ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/133a02c1-df47-eea6-1a7f-d4055f0aa49d.png" />


# 全画面共通のレイアウト作成

## Layoutの作成

ページ全体の配置を整えるための`Layoutコンポーネント`を作成する
Layoutコンポーネントを各ページで用いることで、全ページで共通したスタイリングを適用できる

### 手順

``` bash
    ├── src
    │   ├── components        ←追加する
    │   │   └── layout.js     ←追加する
    │   └── pages
    │       ├── index.js     ←layoutを適用する
    │       └── page2.js     ←layoutを適用する
```

1. `Layoutコンポーネント`を作成する
   コンポーネントの子要素を引数で受け取り、共通のコンポーネントに埋め込んで返却している

    ```react:layout.js
    import React from "react"
    
    const Layout = ({ children }) => {
        return (
            <div className="wrapper">
                <main>{children}</main>
            </div>
        )
    }
    
    export default Layout
    
    ```


1. 作成したLayoutコンポーネントを各ページで使う
    ```react:index.js
        import React from "react";
        import {Link} from "gatsby";
        import Layout from "../components/layout"; ← 追加
        
        
        export default function Home() {
        
          return (
              <Layout>  ← 追加
                <div>Hello world!</div>
                <Link to="/page2">別のページへ</Link>
              </Layout>  ← 追加
          );
        }
    ```
    
    `page2.js`も同様にする


### 【確認】
<img width="400" alt="indexページのイメージ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/bb2126d8-ee78-931a-bc52-47e6819e612b.png" />

<img width="400" alt="page2のイメージ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/a309c3a4-c411-e3b6-1045-809eeed00d1f.png" />



## ヘッダーとフッターを追加

ページ全体の共通コンポーネントの`Layoutコンポーネント`にヘッダーとフッターを追加する

### 手順

``` bash
    ├── src
    │   ├── components
    │   │   ├── header.js     ←追加する
    │   │   ├── fotter.js     ←追加する
    │   │   └── layout.js     ←headerとfotterを適用する
    │   └── pages
    │       ├── index.js
    │       └── page2.js
```

1. Headerコンポーネントを作成する

    ```header.js
        import React from "react"
        import { Link } from "gatsby"
        
        export default function Header() {
            return (
                <header>
                    <h1>MY SITE</h1>
                    <nav class="gnav">
                        <ul class="menu">
                            <li><Link to="/">HOME</Link></li>
                            <li><Link to="/page2">PAGE2</Link></li>
                        </ul>
                    </nav>
                </header>
            )
        }

    ```

1. Fotterコンポーネントを作成する

    ```fotter.js
        import React from "react";
        import Layout from "../components/layout";
        
        
        export default function Page2() {
            return (
                <Layout>
                    <div>Page2です</div>
                </Layout>
            );
        }
    ```

1. CSSを作成する

    <details><summary>CSSはお好みで</summary><div>

    ```css :static/styles/style.css
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        html body {
            height: 100vh;
        }
        
        main {
            height: calc(100vh - 50px); /* 画面 - header */
            padding: 50px 20px;
            margin: 0 auto;
        }
        
        header {
            width: 100%;
            height: 50px;
            padding: 10px;
            background-color: #fff;
            display: flex;
            justify-content: space-between;
            position: fixed;
            top: 0;
            left: 0;
            align-items: center;
            box-shadow: 0 1px 6px 0 rgb(32 33 36 / 28%);
        }
        
        .menu {
            display: flex;
        }
        
        .menu li {
            list-style: none;
        }
        
        .menu li + li {
            margin-left: 40px;
        }
        
        footer {
            width: 100%;
            height: 50px;
            padding: 10px;
            background-color: black;
            color: #fff;
        }

    ```
    </div></details>

1. Layoutコンポーネントにheaderとfotterを追加する
    ```react:layout.js
        import React from "react";
        import Header from "./header"; ←追加
        import Footer from "./footer"; ←追加
        
        const Layout = ({ children }) => {
            return (
                <div className="wrapper">
                    <Header /> ←追加
                        <main>{children}</main>
                    <Footer /> ←追加
                </div>
            )
        }
        
        export default Layout
    ```


### 【確認】
<img width="400" alt="indexページのイメージ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/e42a05e0-9906-570b-6d85-d3acf5011955.png" />

<img width="400" alt="page2のイメージ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/b2b28607-1d3d-3187-617a-c54c01fda9ee.png" />



# 404ページ
Gatsby.jsでは、存在しないページにアクセスすると自動的に404ページにルーティングする
404ページの内容は`src/pages/404.js`に記載することで反映される

:::note info
`gatsby develop`で開発サーバを立ち上げている場合は、無効なURLへアクセスしても404ページは表示されずデバッグ用のページが表示される。
404ページへのルーティングはビルドを行いサーバーを立ち上げたときのみ機能する。
:::

## 404.jsがない場合の表示
- `gatsby develop`の場合
    デバッグ用のページが表示される。
    <img width="400" alt="gatsby developの場合" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/e2a56ada-0a92-f139-9559-e3c5d5d3bd3d.png" />
    
- `gatsby build`→`gatsby serve`
    404のページがないのでルーティングされない。`src/pages/404.js`の作成が必要
    <img width="400" alt="gatsby serveの場合" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/929d1e1d-599b-1f8f-95a5-6fe12ad5d979.png" />
    

## 404.jsがある場合の表示
`src/pages/404.js`を作成して確認する

```react:404.js
import React from "react";
import { Link } from "gatsby";
import Layout from "../components/layout";

export default function NotFound() {
    return (
        <Layout>
            <div className="not-found-message">
                <h1>404 Not Found</h1>
                <Link to="/">トップページへ</Link>
            </div>
        </Layout>
    )
}

```

- `gatsby develop`の場合
    デバッグ用のページが表示される。
    <img width="400" alt="gatsby serveの場合" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/779ea947-bf4e-31df-5b8a-ca19e043b041.png" />


- `gatsby build`→`gatsby serve`
    404のページが表示される
    <img width="400" alt="gatsby serveの場合" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/c24acf75-990a-8bb3-b601-eac72ace039f.png" />




# SEO対策

SEOのためにheadタグの内容を最適化する
Reactではheadタグを管理できる`react-helmet`というライブラリがあるのでそれを使う

## react-helmetの導入

```
$ yarn add --dev react-helmet
```

## SEOコンポーネントの作成

### 手順
1. SEOコンポーネントの作成
    - ページごとに可変の値は引数で受け取って設定する
    - 共通の値は固定で設定する

    ```react:seo.js
    import React from "react";
    import { Helmet } from "react-helmet";
    
    const SEO = ({ title, description }) => {
        return (
            <Helmet
                htmlAttributes={{ lang: "ja-jp" }}
                title={`${title} | My Gatsby Site`}
                titleTemplate={`%s`}
                meta={[
                    {
                        name: `description`,
                        content: description,
                    },
                    {
                        property: `og:title`,
                        content: title,
                    },
                    {
                        property: `og:description`,
                        content: description,
                    },
                    {
                        property: `og:type`,
                        content: `website`,
                    },
                    {
                        property: `og:site_name`,
                        content: `Dev Blog`,
                    },
                    {
                        property: `og:locale`,
                        content: `ja_JP`,
                    },
                ]}
            />
        )
    }
    
    export default SEO
    ```

1. 各ページに追加する。

    ```react:index.js
        import React from "react";
        import Layout from "../components/layout";
        import SEO from "../components/seo"; ←追加
        
        export default function Home() {
        
          return (
              <Layout>
                <SEO title="TOP" description="Gatsbyを使って作ったブログです" /> ←追加
                <div>Hello world!</div>
              </Layout>
          );
        }
    ```

### 【確認】
ページのタイトルが設定された。

<img width="400" alt="index.js" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2728837/8622df54-f41d-7004-1d5f-44dad0d6d5de.png" />