Gatsby v2とNetlifyで運用コストゼロのサービスサイトを作る。ハマった部分とメリットの解説。

## はじめに

はじめてのQiita投稿です。

現在、現役プログラマーとプログラミング学習者を直接つなげるマーケットプレイスCodeGritを開発しています。こちらのサービスで、事前登録、メンター募集を開始するにあたりティーザーサイトを構築しました。

構築したサイト: [CodeGrit](https://www.codegrit.jp/)
<img width="500" alt="top.png" src="https://qiita-image-store.s3.amazonaws.com/0/57656/21b6c371-f6da-5ade-e87e-c0125b10d007.png">


タイトルの通り、Gatsbyを利用したのですがGatsby.jsが現在Version1から2への移行期にあたり、一部混乱のある部分もあったのでこの記事ではハマりそうな部分と、Gatsby.jsとNetlifyを利用するメリットを解説します。

## Gatsby.jsとは? 

[Gatsby.js](https://www.gatsbyjs.org/)は、React製のスタティックサイトジェネレーターです。Gatsbyのガイドラインに沿ってサイトを作成すれば、ProductionビルドをGatsbyが自動でやってくれWebpackなど自分で設定する必要がありません。

もう一つのメリットは、index.html, become-a-mentor.htmlのようなスタティックファイルを生成してくれるので、SSR(サーバーサイドレンダリング)をしなくてもSEOへの悪影響がないことです。(頻繁にコンテンツが更新されるようなWebアプリなどでは別)

## Gatsby.jsを採用した背景

今回Gatsby.jsではなくNext.jsやCreate React Appを使うかも検討したのですがNext.jsでSSRすると、サーバー代がかかってしまうため個人開発者として最低限に運用費を抑えるためGatsbyを選択しました。

また現在CodeGritのサーバーでGraphQL APIを実装しているのですが、Gatsby.jsではコンテンツをGraphQLを利用して(Apollo)引っ張ってくる仕組みがあり、便利だと感じた点も大きいです。

公開中のページではデータを取得していないためGraphQLを利用していませんが、今後はWordpress APIまたはヘッドレスCMSを利用してコンテンツを表示することや、サーバーからメンター情報やコース情報を取得して表示する方向で拡張予定です。

## サイトを実装する

### 全てのプラグインをバージョンnextでインストール

現在、Gatsby.jsはVersion1から2への移行の最中です。Web上にある情報はほとんどがGatsby V1を基準にしているため注意が必要です。僕の場合、最初この２つをごっちゃにしていたため開発中は問題なかったのですがNetlifyへ公開する際にエラーが発生したりレイアウトが上手く表示されない問題が発生しました。

Gatsbyではプラグインと呼ばれるライブラリが多く存在しており、これらのプラグインを利用することで自分でほとんど設定をせずともビルドが出来ます。

これらのプラグインをGatsby Version2に併せて入れるには全てのプラグインのバージョンをnextにする必要があります。また以下のように、gatsbyと元々入っているgatsby-plugin-react-helmetもnextのバージョンを入れ直す必要があります。

```bash
yarn add gatsby@next gatsby-plugin-react-helmet@next
```

また、今回確認出来たところでは以下のプラグインはまだnextのバージョンがないのですが、問題なく利用することが出来ました。

- gatsby-plugin-favicon

### Pagesディレクトリ以下にページごとのTopコンポーネントを置く

Gatsbyでは、Next.jsと同様にpages内にあるコンポーネントが自動的にページとして利用されます。
例えば、今回の場合であれば

- index.js - https://www.codegrit.jp/
- become-a-mentor.js - https://www.codegrit.jp/become-a-mentor/

の2つのページを作成しました。

各ページは、ReactHelmetを利用してヘッドタグ内の情報を書いている以外は、各コンポーネントを呼び出すだけの構成です。例えば、index.jsは以下のようになっています。

```react:src/pages/index.js
import React from 'react'
import Helmet from 'react-helmet'
import Layout from "../components/layout"
import TopHero from '../components/Top/Hero'
import TopFeatures from '../components/Top/Features'
import TopPrograms from '../components/Top/Programs'
import TopHowItWorks from '../components/Top/HowItWorks'
import TopPricing from '../components/Top/Pricing'
import StartNow from '../components/StartNow'
import OgImg from '../images/og_img.png'

const IndexPage = () => (
  <Layout>
    <Helmet>
      <meta property="og:type" content="website" /> 
      <meta property="og:url" content="https://www.codegrit.jp" />
      <meta property="og:title" content="現役プログラマーからプログラミングを学ぼう | CodeGrit" />
      <meta property="og:description" content="CodeGritはプログラミングメンターと学習者を直接つなげるマーケットプレイスです。" />
      <meta property="og:image" content={`https://www.codegrit.jp${OgImg}`} />
      <meta property="fb:app_id" content="1031492147011448" />
      <meta name="twitter:card" content="summary_large_image" />
      <meta name="twitter:title" content="現役プログラマーからプログラミングを学ぼう | CodeGrit" />
      <meta name="twitter:description" content="CodeGritはプログラミングメンターと学習者を直接つなげるマーケットプレイスです。" />
      <meta name="twitter:image" content={`https://www.codegrit.jp${OgImg}`} />
    </Helmet>
    <TopHero />
    <TopFeatures />
    <TopPrograms />
    <TopHowItWorks />
    <TopPricing />
    <StartNow />
  </Layout>
)

export default IndexPage
```

### Glamorousを利用する

CSS in JSのライブラリでは、StyledComponentが最も人気がありますが、僕はGlamorousというライブラリを利用しています。

glamorous: https://glamorous.rocks/

<img width="500" alt="glamorous.png" src="https://qiita-image-store.s3.amazonaws.com/0/57656/40cb45d9-4fee-62ae-994c-ea64cca0223c.png">


glamorousを使うにはプラグインをインストールします。

*公式サイトにも解説があります: https://www.gatsbyjs.org/docs/glamor/


```bash
yarn add gatsby-plugin-glamor@next
```

インストールしたら、gatsby-config.jsにプラグインを追加します。

```javascript:gatsby-config.js
module.exports = {
  plugins: [
    'gatsby-plugin-react-helmet', 
    'gatsby-plugin-glamor',
    ...
}
```

これだけで使えます。例えば、Glamorousを利用してButtonコンポーネントを作ると以下のようになります。

```react:src/components/Button/index.js
import glamorous from 'glamorous';

const Button = glamorous.button({
  color: '#a9a9a9',
  transition: '0.4s',
  textDecoration: 'none',
  padding: '8px 16px',
  borderRadius: 4
}, props => {
  let styles = [];
  switch (props.type) {
    case 'primary':
      styles.push({
        color: '#fff',
        backgroundColor: '#D9728E',
        border: '1px solid #D9728E',
        ':hover': {
          opacity: 0.7
        },
      })
      break;
    default:
      break;
  }
  switch (props.size) {
    case 'large':
      styles.push({
        fontSize: '1.1em',
        padding: '12px 24px',
      })
      break;
    default:
      break;
  }
  return styles;
})

export default Button;
```

上記のようにすると、例えば`<Button type="primary" size="large">テスト</Button>`のようにすることで、大きなサイズのプライマリーボタンを表示することが出来ます。Propsを渡すことでスタイルを簡単に変えられるので便利です。

### Ant Designを利用する

今回、グリッドデザインの部分に対してAnt Designを利用しました。

Ant Design: https://ant.design/

<img width="500" alt="antd.png" src="https://qiita-image-store.s3.amazonaws.com/0/57656/61cc4828-3068-c0ae-a807-9834036d3bff.png">


このAnt Designですが、まだプラグインがnextバージョンに対応していないため以下のような方法を使って設定する必要があります。

1. antd、less, gatsby-plugin-less, babel-plugin-importのインストール

Ant Design

```bash
yarn add antd less gatsby-plugin-less babel-plugin-import
```

2. gatsby-config.jsの設定

まず最初にgatsby-config.jsを編集して、プラグインにgatsby-plugin-lessを追加します。またmodifyVarsの部分でAnt Designのデフォルトのlessのvariablesを上書きします。

```javascript:gatsby-config.js
module.exports = {
  plugins: [
    ...,
    {
      resolve: `gatsby-plugin-less`,
      options: {
        // theme: `./src/layouts/theme.js`,
        javascriptEnabled: true,
        modifyVars: {
          'primary-color': '#722ed1',
          'font-family': '"YuGothic", "遊ゴシック", "Open Sans", "Helvetica Neue"',
          'heading-color': '#001247',
          'primary-color': '#4ECDC4',
          'text-color': '#1B1B1B',
          'border-color-base': 'rgb(228, 228, 228)'
        }
      },
    },
  ]
}
```

3. gatsby-node.jsを編集してantdを読み込む。

次にgatsby-node.jsを編集します。

```javascript:gatsby-node.js
exports.onCreateBabelConfig = ({ actions }) => {
  actions.setBabelPlugin({
    name: 'babel-plugin-import',
    options: {
      libraryName: 'antd',
      style: true
    }
  })
}
```

これで準備完了です。例えばFeaturesというコンポーネントでは以下のようにしてAnt DesignとGlamorousを利用しています。

```react:/src/components/Top/Features/index.js
import React, { Component } from 'react'
import Row from 'antd/lib/row';
import Col from 'antd/lib/col';
import 'antd/lib/row/style';
import 'antd/lib/col/style';
import glamorous from 'glamorous';
import ChatIcon from '../../../images/chat-icon.png'
import VideoChatIcon from '../../../images/video-chat-icon.png'
import MentorIcon from '../../../images/mentor-icon.png'
import ProgramIcon from '../../../images/certificate-icon.png'

const FeatuersWrapepr = glamorous.div({
  paddingTop: 80,
  paddingBottom: 80,
  borderBottom: '1px solid rgb(228, 228, 228)',
  background: '#4ECDC4',
  color: '#fff'
})

const SectionTitle = glamorous.h2({
  color: '#fff',
  marginBottom: '2em',
  fontWeight: 600
})

const FeatuerTitle = glamorous.h3({
  color: '#fff',
  textAlign: 'center',
  marginBottom: '0.5em',
  fontWeight: 600
})

const FeatureImageWrapper = glamorous.div({
  textAlign: 'center',
  marginBottom: '1.5em'
})


class TopFeatuers extends Component {
  render() {
    return (
      <FeatuersWrapepr>
        <div className="container-fluid">
          <Row gutter={32}>
            <Col span={24} className="text-center top-hero-main">
              <SectionTitle>CodeGritの特徴</SectionTitle>
            </Col>
          </Row>
          <Row gutter={32}>
            <Col sm={24} md={12} lg={6} className="row-space-sm-4 features-video-chat">
              <FeatureImageWrapper>
                <img src={VideoChatIcon} height={"120px"} />
              </FeatureImageWrapper>
              <div className="features-main">
                <FeatuerTitle>ビデオ通話</FeatuerTitle>
                <p>
                  毎週のマンツーマンでのビデオ通話を通じて、学習中の疑問を解決。
                </p>
              </div>
            </Col>
            <Col sm={24} md={12} lg={6} className="row-space-sm-4 features-video-chat">
              <FeatureImageWrapper>
                <img src={ChatIcon} height={"120px"} />
              </FeatureImageWrapper>
              <div className="features-main">
                <FeatuerTitle>チャット</FeatuerTitle>
                <p>
                  チャットを通じて、いつでもメンターに分からないことを質問出来ます。
                </p>
              </div>
            </Col>
            <Col sm={24} md={12} lg={6} className="row-space-sm-4 features-video-chat">
              <FeatureImageWrapper>
                <img src={ProgramIcon} height={"120px"} />
              </FeatureImageWrapper>
              <div className="features-main">
                <FeatuerTitle>学習プログラム</FeatuerTitle>
                <p>
                  CodeGritのオリジナル教材を利用してプログラミングの知識を効率的に学習出来ます。
                </p>
              </div>
            </Col>
            <Col sm={24} md={12} lg={6} className="row-space-sm-4 features-video-chat">
              <FeatureImageWrapper>
                <img src={MentorIcon} height={"120px"} />
              </FeatureImageWrapper>
              <div className="features-main">
                <FeatuerTitle>メンター</FeatuerTitle>
                <p>
                  CodeGritでは現役のプログラマーの方と一人一人メンターしてメンターを採用しています。
                </p>
              </div>
            </Col>
          </Row>
        </div>
      </FeatuersWrapepr>
    );
  }
}

export default TopFeatuers;
```

上記のように、

```javascript
import Row from 'antd/lib/row';
import Col from 'antd/lib/col';
import 'antd/lib/row/style';
import 'antd/lib/col/style';
```

のようにしてAnt DesignのRow、ColのコンポーネントとそのCSSファイルを読み込んでいます。


## Netlifyを利用する

Gatsbyを利用したサイトを公開する方法は公式サイトにもいくつか紹介されています。僕の場合は自動的にLet's Encryptを設定してくれたり、masterブランチへのpushを自動更新してくれ、しかも無料で利用できるということもありnetlifyを選択しました。

Netlify: https://www.netlify.com/
<img width="500" alt="netlify.png" src="https://qiita-image-store.s3.amazonaws.com/0/57656/274eb530-bbfb-ec61-a1b6-d87ebb445661.png">


その他の選択肢については公式サイトを見てみてください。
Deploy: https://www.gatsbyjs.org/docs/deploy-gatsby/

Netlifyを利用してサイトを公開するのは非常に簡単で、まずはGitLabあるいはGitHubにコードをPushして、Netlify上でコードのあるリポジトリを選択するだけです。

デプロイの最中にエラが出たさいにはログが見られるので、こちらを見て問題を解決して再度デプロイすればオーケーです。

デプロイが出来たらDNSを設定して独自ドメインを利用し、またサイト上でhttps利用を申請ボタンをクリックするとLet's Encryptを設定してくれます。

## まとめ

いかがだったでしょうか、サイト運用費を出来るだけ下げたい場合、GatsbyとNetlifyを組み合わせはとてもおすすめです。Gatsbyがビルドなども全てしてくれて手間も少ないのでぜひ試していただければと思います。

また、CodeGritでは現在HTML/CSSとJavaScriptを教えることの出来るメンターの方も募集中です。

教える際の時間単価は自分で設定出来て、教える人数も調整出来るので、副業として数人だけ教えたいという場合も、フルタイムに近い形で教えたいという場合も大歓迎です。ぜひ以下のページよりご応募ください。

メンター募集 - https://www.codegrit.jp/become-a-mentor/