Gatsbyを最速で理解するためのチュートリアル

Gatsbyを触ってみたのですがチュートリアルだけだと??となる部分がいくつもあり結局ドキュメントをたくさん読むハメになりました。
ドキュメントのリンクを整理してたらいい感じのチュートリアルができたので投稿しました(所々中途半端ですが・・・)

（追記）実際にブログを作るときは[こちら](https://qiita.com/abouch/items/2668fbc185b8dc7b659c)も参照いただけると良いかもです。


## Install

```
npm install -g gatsby-cli
```

```
gatsby new [rootPath] [starter]  Create new Gatsby project.
```

[starter](#starter)を指定する。デフォルトではdefault starterが選択されます。



チュートリアルなのでhello-world一択。

```
gatsby new my-blog https://github.com/gatsbyjs/gatsby-starter-hello-world
```

```
gatsby develop
```


一応npm scriptにも書かれています。

```
npm run develop 
```

```　.json
 "scripts": {
    "develop": "gatsby develop"
  }
```


`-p`オプションで別のポートを指定することができるので複数のプロジェクトを立ち上げたいときに。

```
gatsby develop -p 3000
```

[CLI](https://www.gatsbyjs.org/docs/gatsby-cli/)のドキュメントまで丁寧にあります。

デフォルトだとhttp://localhost:8000/ でページにhttp://localhost:8000/___graphql でGrqphiQLにアクセスできます。

## 入門

### Page

ディレクトリの構成にルールがあって`pages/`が自動でページなります。
例えば`pages/about.js`を作成すると`/about`で表示されます(ページが生成されてルートが設定される)


``` pages/index.js
import React from 'react'

export default <div> index page </div>
```

``` pages/about.js
import React from 'react'

export default <div> hello page </div>
```

その他は`components/`に共通コンポネントを作成するなど普通のReactのアプリケーションのようにを開発できます。


> Any React component defined in src/pages/*.js will automatically become a page.

[using-page-components](https://www.gatsbyjs.org/tutorial/part-one/#-using-page-components)


またテンプレートファイルを作成して動的にページを生成することも可能です。[creating-pages-automatically](https://www.gatsbyjs.org/docs/recipes/#creating-pages-automatically)


### GraphQL

gatsbyの便利な点はプロジェクト内のデータをGraphqlで取得できるところです。


例えばProjectの[設定](https://www.gatsbyjs.org/docs/gatsby-config/#configuration-options)情報は以下のqueryで取得できます。


configファイルを以下のように変更します。


``` javascript
module.exports = {
  siteMetadata: {
    title: `Title from siteMetadata`,
  }
}
```



```
  query {
    site {
      siteMetadata {
        title
      }
    }
  }
```

[デモ](http://localhost:8000/___graphql?query=%20%20query%20%7B%0A%20%20%20%20site%20%7B%0A%20%20%20%20%20%20siteMetadata%20%7B%0A%20%20%20%20%20%20%20%20title%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D)


このようにプロジェクトの情報をqueryで取得して、それを表示するReactのコンポネントを作成し、それを元にgatsbyがページを生成するという流れになります。

[use-a-page-query](https://www.gatsbyjs.org/tutorial/part-four/#use-a-page-query)


このGraphQLですがデータを追加する作業とデータを取得する作業の二つに分けて理解するのがいいと思います。



---

まずデータを追加する作業から見ていきます。
後述するプラグインを入れる事でプロジェクト内の情報を自由に取得できるようになります。

[adding-data-to-graphql](https://www.gatsbyjs.org/docs/recipes/#adding-data-to-graphql)

#### プラグインからデータを追加する

データを追加する作業はドキュメントに`plugin driven`と書かれていて、実際プラグインを入れるだけです。

[sourcing-data](https://www.gatsbyjs.org/docs/recipes/#5-sourcing-data)


##### gatsby-source-filesystem

例えば`gatsby-source-filesystem`を使うことでソースからデータを取得できるようになります。

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

``` gatsby-config.js.js
module.exports = {
  siteMetadata: {
    title: `Pandas Eating Lots`,
  },
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `src`,
        path: `${__dirname}/src/`,
      },
    }
  ]
}
```

graphiqlを開くと`allFile`と`file`が新たに追加され、以下のqueryでファイル情報を取得できるようになります。


``` .graphql
  query {
    allFile {
      edges {
        node {
          relativePath
          prettySize
          extension
          birthTime(fromNow: true)
        }
      }
    }
  }
```

https://www.gatsbyjs.org/tutorial/part-five/


チュートリアルではプロジェクトのJSファイルを取得して表示しています。



##### [gatsby-transformer-remark](https://www.gatsbyjs.org/packages/gatsby-transformer-remark/)

https://www.gatsbyjs.org/docs/adding-markdown-pages/#transform-markdown-to-html-and-frontmatter-to-data-using-gatsby-transformer-remark

これはデータを追加するだけのプラグインではないので、この流れで書くのも微妙なのですが
このプラグインがやってくれる一番わかりやすいのはmarkdownを変換してくれるところです。mdファイルの情報をhtmlに変換して取得できたり、frontmatterなどのメタ情報を取得できます。

`allMarkdownRemark`というのが追加されます。

#### 自分でデータを追加する

createNodeAPIを使って自分でデータを流すことができます。後述しますがプラグインはこのAPIを使ってデータを流しています。

#####  手動でデータを入れてみる

<details><summary>ポケモンのデータを入れてみる</summary><div>

``` .js
exports.sourceNodes = ({ actions, createNodeId, createContentDigest }) => {
  const pokemons = [
    { name: "Pikachu", type: "electric" },
    { name: "Squirtle", type: "water" },
  ]
  pokemons.forEach(pokemon => {
    const node = {
      name: pokemon.name,
      type: pokemon.type,
      id: createNodeId(`Pokemon-${pokemon.name}`),
      internal: {
        type: "Pokemon",
        contentDigest: createContentDigest(pokemon),
      },
    }
    actions.createNode(node)
  })
}
```

</div></details>


以下のqueryでポケモンを取得できるようになります。

``` .graphql
query MyPokemonQuery {
  allPokemon {
    nodes {
      name
      type
      id
    }
  }
}
```

外部から取得したデータを流すこともできる。

##### APIから取得したデータを流してみる


<details><summary>QiitaのAPIからデータを流してみる</summary><div>


この辺のAPIは詳しく確認してないので、少し修正しただけですが、

``` .js
const fetch = require("node-fetch")

const fetchItems = () =>
  fetch("https://qiita.com/api/v2/items").then(res => res.json())

exports.sourceNodes = async ({
  actions,
  createNodeId,
  createContentDigest,
}) => {
  const items = await fetchItems()
  items.forEach(item => {
    const node = {
      id: item.id,
      title: item.title,
      user: {
        name: item.user.name,
      },
      internal: {
        type: "Item",
        contentDigest: createContentDigest(item),
      },
    }
    actions.createNode(node)
  })
}
```


``` .graphql
query ItemQuery {
  allItem {
    nodes {
      title
      user {
        name
      }
    }
  }
}
```

``` 
{
  "data": {
    "allItem": {
      "nodes": [
        {
          "title": "blob & createObjectURL について ",
          "user": {
            "name": "Yu Watanabe"
          }
        },
      ]
   }
  }
}
```

QiitaのAPIからとってきた情報を流す事で、queryで取得できるようになりました。

</div>
</details>


先ほどの[gatsby-source-filesystem](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-filesystem/src/gatsby-node.js)もこのcreateNodeを使ってローカルのファイル一覧を取得して流し込んでいるのがわかると思います。


ファイルの情報を流すとかwordpressから記事を取得して流すといったことをやってくれるプラグインがあるので、我々は設定ファイルにパスだったりurlを入れるだけでqueryでデータを取得できるようになります。

[pixabay-source-plugin-tutorial](https://www.gatsbyjs.org/docs/pixabay-source-plugin-tutorial/)

そしてqueryで取得した結果をページに表示するだけでいいのです。


#### nodeを追加する

nodeにfieldを追加することができます。

[creating-slugs-for-pages](https://www.gatsbyjs.org/docs/creating-slugs-for-pages/#create-slugs-in-gatsby-nodejs)

``` .js
const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark`) {
    const slug = createFilePath({ node, getNode, basePath: `pages` })
    createNodeField({
      node,
      name: `slug`,
      value: slug,
    })
  }
}
```

が追加されてslugが取得できるようになった。

```
query  {
  allMarkdownRemark {
    edges {
      node {
        id
        fields {
          slug
        }
      }
    }
  }
}
```

#### Query

GraphQLを初めて触る人もいるかもしれませんがサイトを作るだけであれば[レファレンス](https://www.gatsbyjs.org/docs/graphql-reference/)の内容で十分だと思います。またGrqphiqlで左側をぽちぽち動かせば勝手にquery作ってくれるので特に困ることもないかと思います。


<img width="337" alt="スクリーンショット 2019-12-07 20.36.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166241/c08405e5-0c4f-c73e-cd25-76e98826ab99.png">

##### alias


`allMarkdownRemark`の結果はそのままだと`data.allMarkdownRemark`ですが、先頭に任意のaliasをつけることができます。
`data.latestPost`, `data.relatedPost`のように帰ってきます。

```
query {
  latestPost: allMarkdownRemark(limit: 5) { }
  relatedPost: allMarkdownRemark(limit: 5) { }
}
```

##### frontmatter

マークダウンファイルの先頭に以下のように情報を定義します。

``` .md
---
title: my first post
date: 2019-12-7
---
```

先ほどの`gatsby-transformer-remark`を使うことで以下のqueryで取得することができます。



```
frontmatter {
  title:
  date:
}
```



##### params

どちらかというと`markdown-remark`の話ですが、


- limit

```
 allMarkdownRemark(limit: 5) { }
```

- format

```
date(formatString: "YYYY月MM月DD日")
```

- filter

```
filter: { tags: { in: ["post", "page"] }, draft: { eq: false } }
```






##### 直近の投稿5件を取得するQuery

```
query {
  allMarkdownRemark(
    limit: 5,
    sort: {order: DESC, fields: frontmatter___create_at}
  ) {
    edges {
      node {
        id
        frontmatter {
          title
        }
      }
    }
  }
}
```



### 動的にページを生成する。

#### ページから必要なデータを取得する

実際にGraphQLからデータを取得してページに表示していきます。


``` .js
import React from "react"
import { graphql } from "gatsby"

export const query = graphql`
  query TitleQuery {
    site {
      siteMetadata {
        title
      }
    }
  }
`
export default ({ data }) => (
  <div>
    <h1>{data.site.siteMetadata.title}</h1>
  </div>
)
```

[page-query](https://www.gatsbyjs.org/docs/page-query/)


- １つのファイルにつき１つのqueryを宣言できる。この時変数は関係ない。
- queryの結果がpropsのdataオブジェクトに入ってくる。

チュートリアルには書かれていないのですが、上記のルールがあります。




試しに一つのファイルに二つのqueryを宣言してみたら怒られました。

```
export const query1 = graphql`
  query HomePageQuery {
    site {
      siteMetadata {
        description
      }
    }
  }
`
export const query2 = graphql`
  query HomePageQuery {
    site {
      siteMetadata {
        description
      }
    }
  }
`
```


```
Multiple "root" queries found in file
```

初めてこれを見たときは、どうしてpropsのdataにqueryの結果が渡ってくるんだ？いつqueryは実行されるという気持ちになったのですが、今使っているのは静的サイトジェネレーターでなので、お作法に従ってファイルにqueryを定義すればそれをもとにページ生成してくれるということを忘れていました。


https://www.gatsbyjs.org/docs/recipes/#querying-data-with-a-page-query
https://www.gatsbyjs.org/docs/page-query/#add-the-graphql-query


#### 動的にページを生成する

`createPage` APIを使ってテンプレートから動的にPageを生成します。

チュートリアルの[part７](https://www.gatsbyjs.org/tutorial/part-seven/)でこんな感じになると思います。


``` gatsby-node.js
const path = require(`path`)

exports.createPages = async ({ actions, graphql }) => {
  const result = await graphql(`
    {
      allMarkdownRemark {
        edges {
          node {
            frontmatter {
              path
            }
          }
        }
      }
    }
  `)

  if (result.errors) { console.error(result.errors) }

  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    actions.createPage({
      path: node.frontmatter.path,
      component: path.resolve(`src/templates/post.js`),
    })
  })
}
```


``` src/templates/post-template.js
import React from "react"
import { graphql } from "gatsby"

export const pageQuery = graphql`
  query($path: String!) {
    markdownRemark(frontmatter: { path: { eq: $path } }) {
      html
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        path
        title
      }
    }
  }
`

const Template = ({ data }) => {
  const { markdownRemark } = dat
  const { frontmatter, html } = markdownRemark
  return (
    <div className="blog-post">
      <h1>{frontmatter.title}</h1>
      <h2>{frontmatter.date}</h2>
      <div
        className="blog-post-content"
        dangerouslySetInnerHTML={{ __html: html }}
      />
    </div>
  )
}

export default Template;
```

まず、テンプレートファイルを見てみます。テンプレートファイルはpathパラメータを使ったqueryの結果を埋め込むようになっています。

`gatsby-node.js`では全てのmdファイルのquery結果を元に`createPage`メソッドを読んでいます。
このメソッドが上のテンプレートファイルを指定していて、動的にページが生成されます。
想像はつくもののチュートリアルに書かれていない大事な点は引数のcontextがtemplateのpropsとtemplateファイルのqueryの引数として渡せる点です。


https://www.gatsbyjs.org/docs/recipes/#sourcing-markdown-data-for-blog-posts-and-pages-with-graphql
https://www.gatsbyjs.org/docs/using-gatsby-without-graphql/


[onCreatePage](https://www.gatsbyjs.org/docs/node-apis/#createPages)


>  All context values are made available to a template’s GraphQL queries as arguments prefaced with $

https://www.gatsbyjs.org/docs/programmatically-create-pages-from-data/#creating-pages


[createPage](https://www.gatsbyjs.org/docs/actions/#createPage)


> pased as props to the component this.props.pageContext as well as to the graphql query as graphql arguments.

ソースを探すの少し時間がかかりました。



## 概念的な

#### Starter


- gatsby-starter-default	
- gatsby-starter-blog	
- gatsby-starter-hello-world	

公式のstarterは実は上の３つだけ。

https://www.gatsbyjs.org/docs/starters/


スターター一覧
https://www.gatsbyjs.org/starters/?v=2



```
gatsby new gatsby-starter-hero-blog https://github.com/greglobinski/gatsby-starter-hero-blog
```

https://www.gatsbyjs.org/starters/greglobinski/gatsby-starter-hero-blog/

これはちょっと重かった。


#### Plugin

https://www.gatsbyjs.org/docs/plugins/

```
npm install --save gatsby-transformer-json
```

```
module.exports = {
  plugins: [`gatsby-transformer-json`],
}
```

Pluginは任意のOptionを指定できる。

``` .js
  plugins: [
    // Shortcut for adding plugins without options.
    "gatsby-plugin-react-helmet",
    {
      // Standard plugin with options example
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/data/`,
        name: "data",
      },
    }
  ]
```

https://www.gatsbyjs.org/docs/using-a-plugin-in-your-site/


StyledComponentsやaxiosなどのnpx packageを使うには

https://www.gatsbyjs.org/docs/what-you-dont-need-plugins-for/

ローカルのパスを指定してプラグインを入れることもできる。

https://www.gatsbyjs.org/docs/loading-plugins-from-your-local-plugins-folder/



#### Config

https://www.gatsbyjs.org/docs/api-files-gatsby-node/

##### gatsby-config.js

##### gatsyby-node.js

build時に一度だけ呼ばれ、動的にページを生成したり、GraphQLのnodeを追加したりする。


https://www.gatsbyjs.org/docs/api-files-gatsby-node/

## 実践編


```
gatsby new blog https://github.com/gatsbyjs/gatsby-starter-hello-world
```



#### styled-componentsを使う

https://www.gatsbyjs.org/docs/styled-components/

モジュールとプラグインを入れます。

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

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

#### typescriptを使う

あまり参考になるかはわかりませんが、Pluginを入れる必要があります。

https://github.com/gatsbyjs/gatsby/tree/master/examples/using-typescript

https://www.gatsbyjs.org/packages/gatsby-plugin-typescript/?=type


```
npm install gatsby-plugin-typescript
```


``` .json
{
  "include": ["./src/**/*"],
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "lib": ["dom", "es2017"],
    "jsx": "react",
    "strict": true,
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "noEmit": true,
    "skipLibCheck": true
  }
}
```

Typescriptを使うメリットがどれくらいあるかだが、公式がPropsTypesで頑張ってるのをみると入れてもいいと思う。



#### Syntax Hilight

GatsbyのPluginにのっかって楽をするだけであればプラグイン入れるだけです。


```
npm i -S gatsby-remark-prismjs
```


`gatsby-transformer-remark`のpluginに追加してあげます。

``` javascript
plugins: [
  {
    resolve: `gatsby-transformer-remark`,
    options: {
      plugins: [
        `gatsby-remark-prismjs`,
      ]
    }
  }
]
```

先ほどのqueryがclassつきのhtmlを取得できます。
あとは自分でstyleを指定してもいいですが、標準で用意されているテーマを読み込んであげるだけです。

`gatsby-browser.js`

``` javascript
require("prismjs/themes/prism-solarizedlight.css")
```


https://www.gatsbyjs.org/packages/gatsby-remark-prismjs/


#### Tag振り分け

https://www.gatsbyjs.org/docs/adding-tags-and-categories-to-blog-posts/

#### SEO

SEOコンポネントがドキュメントに掲載されています。

https://www.gatsbyjs.org/docs/add-seo-component/



#### Deploy(GitHub-Pages)

プラグイン入れてpushするだけです。

https://www.gatsbyjs.org/docs/how-gatsby-works-with-github-pages/



#### Plugin

エディターのpluginを使えばgraphqlの入力に補間が効くかも・・

## 感想

簡単簡単と言われているのでQiitaのチュートリアル見ながら３０分くらいでいけるのかと思ったのですが、結局ドキュメントをたくさん読むハメになり結構時間がかかってしまいました。
チュートリアルだけではなんで？っていいうお気持ちになるので、余力があれば[recipes](https://www.gatsbyjs.org/docs/recipes/)と[content-and-data](https://www.gatsbyjs.org/docs/content-and-data/)をみると理解が早まるのでお勧めです。お作法に従って書くのが苦手でなければかなり簡単だと思います。
というか長々とかきましたがお気に入りのstarterから初めて少し変更するぐらいが一番コスパが良いと思います。