The source code for this blog is available on GitHub.

Blog.

Gatsbyを学ぶ

Cover Image for Gatsbyを学ぶ

下記を参考に。

作業時間:12時間 経過時間:44時間

Gatsby.js×Contentful×Netlifyの構成に変更した。 振り返り。

GraphQLとは

RESTとは、どう違うのか。 RESTはアーキテクチャ、設計、考え方。

  • アドレス指定可能
  • インターフェースの統一(CRUD)
  • ステートレス(状態を保持しない)
  • 結果がステータスコードで返される
  • and more...

GraphQLはクエリ言語とスキーマ言語から成る。 エンドポイントは1つ。 必要なデータだけをリクエストしレスポンスできる。 ※SQL(構造化問い合わせ言語)はDBに対して問い合わせる、GraphQLはAPIに対して問い合わせる言語。

githubで検証できる。 https://developer.github.com/v4/explorer/

query

例えば、以下。 リクエストの構造がサービスやプロジェクトによって変化する。 viewerをオブジェクト、nameをフィールドと呼ぶ。

//リクエスト
{
  viewer {
    name
  }
}
//レスポンス
{
  "data": {
    "viewer": {
      "name": "sugi"
    }
  }
}

データを特定の項目でフィルタする場合は、以下のようにフィールドに対して引数を指定する。

//リクエスト
{
  viewer {
    name
    repository(name: "blog") {
      id
    }
  }
}
//レスポンス
{
  "data": {
    "viewer": {
      "name": "sugi",
      "repository": {
        "id": "MDEwOlJlcG9zaXRvcnkyNzE0NDQ4Mzc="
      }
    }
  }
}

$で変数を渡せることを定義。!は引数が必須であることを明示する。

query ($organization: String!) {
  organization(login: $organization) {
    name
    url
  }
}

クエリに名前をつけられる。「オペレーションタイプ」、「オペレーションネーム」と呼ばれる。

query test{
  organization(login: $organization) {
    name
    url
  }
}

ディレクティブ @include,@skipで特定のフィールドの取得を操作できる

mutation

データの更新をさせたい場合に使用する。

プラグイン

公式でたくさん紹介されていた。今回利用したものを抜粋。

gatsby-plugin-postcss

postcssをgatsbyで扱うのに使用、postcssはtailwindcssを使用するために使いたかった。

gatsby-transformer-remark

contentfulを使用していて、markdownを使っていたが、htmlに置き換える必要があったので利用。

gatsby-remark-prismjs

markdownの中でハイライトしたいコードがあったので、導入。

gatsby-plugin-react-helmet

title要素を操作するために、導入。

構成

動画を見つつ作成した、最終的な構成は以下。 ※一部のファイルは省略。

├──src
│   ├── components
│   │   ├── footer.js
│   │   ├── head.js
│   │   ├── header.js
│   │   └── layout.js
│   ├── pages
│   │   ├── 404.js
│   │   ├── blog.js
│   │   └── index.js
│   ├── styles
│   │   └── tailwind.css
│   └── templates
│       └── blog.js
│
├──.env
├──.gatsby-config.js
├──.gatsby-node.js
├──postcss.config.js
└──tailwind.config.js

ルーティング

contentfulとgatsbyのファイルの照合の仕組み。 contentfulで定義したslugをもとに、gatsbyのどのファイルでレンダリングするかを決めて行う。.gatsby-node.jsが担当している。module.exports.createPagesで作成。 graphqlを使用して、contentfulのスラッグの値を取得、createPageでファイル、パス、コンテキスト等を指定する。

localhost://8000/___graphqlでテストできる。

.envで以下を定義すると、上記のUIが変わる。

GATSBY_GRAPHQL_IDE=playground

左にリクエスト、右にレスポンスが表示される。 左下のQUERY VARIABLUESには、静的なデータを定義して、クエリの変数に渡せる。 例えば、

//QUERY VARIABLUES
{
  "slug":"react-study-10"
}
//クエリ:$slugには、react-study-10が渡る。
query($slug: String!){
  contentfulBlog(slug: {eq: $slug}){
    title
    createdAt(formatString:"MMMM Do, YYYY")
    main{
      childMarkdownRemark {
        html
      }
    }
  }
}
//gatsby-node.js
module.exports.createPages = async({graphql,actions}) => {
  const {createPage} = actions
  const blogTemplate = path.resolve('./src/templates/blog.js')
  const res = await graphql(`
    query {
      allContentfulBlog {
        edges {
          node {
            slug
          }
        }
      }
    }
  `)
  res.data.allContentfulBlog.edges.forEach(edge => {
    createPage({
      component: blogTemplate, //レンダリングするファイル指定
      path: `/blog/${edge.node.slug}`, //レンダリングするパス指定
      context: { //レンダリングするファイル内でアクセスしたいオブジェクトを指定
        slug: edge.node.slug,
      }
    })
  });
}

1ファイルにつき、1クエリの定義。queryの結果がdataに渡る。

//templates/blog.js
...
export const query = graphql`
query($slug: String){
  contentfulBlog(slug: {eq: $slug}){
    title
    createdAt(formatString:"MMMM Do, YYYY")
    main{
      childMarkdownRemark {
        html
      }
    }
  }
}
`
const Blog = props => {
  return (
    <Layout>
        <Head title={props.data.contentfulBlog.title} />
        <h1>{props.data.contentfulBlog.title}</h1>
        <p>{props.data.contentfulBlog.createdAt}</p>
        <div
          className="body"
          dangerouslySetInnerHTML={{
            __html: props.data.contentfulBlog.main.childMarkdownRemark.html,
          }}
        />
    </Layout>
  )
}

困ったところ

env-cmd

動画にはなかったが、オプションの指定が必要だった。

最初は以下との指定だった。 env-cmd .env gatsby develop 正しくは以下の指定だった。 env-cmd -f .env gatsby develop

pathのエラー

graphqlでブログ詳細ページの動的レンダリングをスムーズに出来なかった。 プレイグランドでは、レスポンスが返されたので、nodeに問題がありそうな気はした。 エラーは以下が返されていた。

Error: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined

調べた感じでは、たしかにnodeに関連する情報が出たが、今回の事象と結び付けられなかった。

とりあえず以下のプラグインを使用しなくなったので、 アンインストールしてdevelopしたら上手くいってしまった。 関連性が分からない。。

//gatsby-config.js
...
plugins: [
'gatsby-plugin-sharp',
 {
 options: {
  plugins: [
    'gatsby-remark-relative-images',
    {
      resolve: 'gatsby-remark-images',
      options: {
        maxWidth: 750,
        linkImagesToOriginal: false
      }
    },
    ...
 }
]

作業環境

解決していない。 ローカル環境が異様に遅いのどうにかならないかな。。

次回

テストやhookとかあるけど、reduxやるか。


More Stories