Open4

microCMS+Gatsby実装メモ

mottox2mottox2

リンク集

検証用リポジトリ

File System Route API | Gatsby
gatsby/examples/route-api at master · gatsbyjs/gatsby

microCMS | APIベースの日本製ヘッドレスCMS
wantainc/gatsby-source-microcms: Source plugin for Gatsby from microCMS.

データの定義

Post, Tag, Categoryみたいな感じでそれっぽいデータを定義した。
API形式は「リスト形式」を選択する。

テーブル設計と同じでTag, Categoryを定義してからPostを定義すると変更が少なくてよい

エンドポイントは単数にすること

APIの型がリスト形式でもエンドポイントは単数にする必要がある。
元々Railsでウェブアプリケーション開発を覚えた人間なので非常に違和感がある。

ここを複数形にしてgatsby-source-microcmsで読み込むとmicrocmsPostsと名前でありながら単数のオブジェクトが帰ってくるQueryが生成される。
これはさすがに直感と反するので、APIを単数形にするほうが良い

mottox2mottox2

File System Route API

Gatsby 2.26で追加されたFile System Route APIを使う。
今までは動的ルーティングはgatsby-node.jsを使う必要があったが、Next.jsやNuxt.jsでも使われているようなファイルシステム上で設置したファイルで動的ルーティングが可能になった。
ただし、File System Route APIには静的なページをビルドするCollection routesとビルド時には静的ページの生成を行わないClient-only routesの2種類がありそれぞれ記法が異なる。

基本的にGatsbyを使う場合はすべてのページをビルドするのでCollection routesを使えばOK。
Client-only routesはクライアントだけであればいい場合はもちろん、データがあるけどページは生成されていないようなfallbackにも使えるらしい。正直そのユースケースならNext.jsの方がマッチしてそう。

microcmsPostでの実装例

src/pages/posts/{microcmsPost.postId}.tsxというファイルを作成する。{}で囲って、GraphQLの型とフィールド名を含めておく。正直気持ち悪さはある。

queryでidを引数にとったGraphQLクエリをexportを行う必要があるらしい。
これはファイル名に含まれるフィールド(この場合はpostId)とは無関係らしい。単純にid固定っぽい。ハマった。

src/pages/posts/{microcmsPost.postId}.tsx
import React from "react"
import { graphql } from "gatsby"

const PostPage = props => {
  return <pre>{JSON.stringify(props, null, 2)}</pre>
}

export default PostPage

export const query = graphql`
  query($id: String!) {
    microcmsPost(id: { eq: $id }) {
      title
      postId
    }
  }
`

実装例という意味では公式リポジトリのexampleを見るのがよさげ
https://github.com/gatsbyjs/gatsby/tree/master/examples/route-api

mottox2mottox2

一覧からのリンク

ドキュメントを見ると、以下のような実装を行っていた。
graphqlのヘルパーとして提供されているgatsbyPathを使ってLinkにわたすためのパスを返してくれる。

src/pages/index.js
import React from "react"
import { graphql } from "gatsby"

const IndexPage = (props) => (
    <pre>
      {JSON.stringify(props.data, null, 2)}
    </pre>
)

export const query = graphql`
  query allPost {
    allMicrocmsPost {
      nodes {
        title
        postId
        postPath: gatsbyPath(filePath: "/posts/{microcmsPost.postId}")
      }
    }
  }
`

export default IndexPage

ただし、Gatsby初心者に教える際にこのヘルパーを教えるか?と聞かれたら理解の妨げになるそうなのでかなり迷う。おそらく以下のようなtemplate literalを使ってパスを構築する方法を教えると思う。

  <Link to={`/posts/${post.postId}`}>Go to post page</Link>

しかし、メリットがないわけではなく、gatsbyPathにわたすfilePathが間違っていた場合にエラーを吐いてくれたりする。大規模なサイトで変更漏れを防いだり、レンダリング前にパスを構築するのでわずかに計算量が減るという観点では意味があるのかもしれない。

例えばこんなエラー

PageCreator: To query node "gatsbyPath" the "filePath" argument must represent a file that exists.

ページネーション

ページネーションは以前のgatsby-node.jsを使う方法しかなさそう?
動的ルーティングの定義方法が混在するのは微妙じゃないだろうか?

mottox2mottox2

Tips: 新しいデータソースを利用する流れ

  1. gatsby-config.jsでソースプラグインを導入する。または自分でデータソースを作るプログラムをgatsby-node.jsに書く
  2. gatsby developでgraphiqlを立ち上げ、アプリケーションで使いたいデータをGraphQLで取得できることを確認する
  3. アプリケーション内でデータを利用する処理を書く。
  • gatsby-node.jsでcreatePageを叩く処理
  • 既存ページのpageQueryやstaticQueryを利用した処理

Tips: デバッグ手法

  • gatsby-node.jsではこまめにconsole.logで見る。毎回gatsby developする必要はある。
  • Reactコンポーネント側ではconsole.logのJSX内に{JSON.stringify(data, null, 2}}などの記法でJSONを見る。