Gatsbyで型安全なブログ開発 | りゅーそうブログ
りゅーそうブログのロゴ

Ryusou.dev

Gatsbyで型安全なブログ開発

gatsby

microcms

typescript

2020/05/12

2022/01/23

今回はGatsbyについての話題です。
特に新しい情報ではなく、「巨人の肩に乗る」的なやつでしょうか。Gatsbyでなかなか良いブログの開発体験が得られたので共有しようと思います。

以下の記事をmicroCMSを用いてやってみましたという記事です。
[Gatsby.jsを完全TypeScript化する]

元記事要約

上記のリンクを読んでください。

  • GatsbyをTypeScript対応する
  • gatsby-plugin-graphql-codegenを用いて型定義を自動生成
  • gatsby-node.jsをTypeScript対応。
  • 静的ページ/動的なページもgatsby-plugin-graphql-codegenで生成した型で開発が可能


Gatsbyのメリット

GatsbyのメリットとしてgraphQLを用いてデータ取得ができるということが挙げられます(独特な書き方でもあるため、毛嫌いされる一要因にもなっていますが)。Gatsbyを使用するのであれば、このgraphQLのメリットを生かして型安全なコードをできるだけ楽に書きたいというモチベーションがありました。
そういった意味でも上記の記事はとても良かったです。

gatsbyを知らない方のために以前記事を書きました。こちらで概要を掴んでみてください。
JamstackなWebサイト制作

ex)Gatsbyの開発の様子①


GatsbyのGraphQLクエリをブラウザで叩く様子
上記のような画面をgatsby developコマンドで表示させることができます。
お使いのheadlessCMSやAPIの情報と紐づけることでブラウザ上でgraphQLのクエリを定義したり、試すことができます。図はmicroCMSで作成したAPIを叩いた様子です。

ex)Gatsbyの開発の様子②


①で試したクエリを実際にコードで定義していきます。

const query = `
{
  allMicrocmsPosts {
    edges {
      node {
        postsId
        title
        tags {
          id
          name
        }
        day
        image {
          url
        }
        content
      }
    }
  }
}
`;


このように定義したスキーマからgatsby-plugin-graphql-codegenを用いて型を自動生成することができます。
参考:gatsby-plugin-graphql-codegen

microCMSでのユースケース

gatsby-plugin-graphql-codegenの使用方法などは冒頭の参照記事に詳しいのでそちらをご参照ください。
当記事では、microCMSでのユースケースを紹介したいと思います。
microCMSをGatsbyで使用するにはgatsby-source-microcmsというプラグインを使用します。
使用方法は公式をご参照ください。
gatsby-source-microcms

静的なページを作成

gatsby-plugin-graphql-codegenを使用し、元記事のように設定を行うと、ビルド時にgraphql-types.tsファイルが自動生成されます。
これを使用して、型定義を行うことができます。
例えば、このようなクエリをエクスポートします(例は私が作成したmicroCMSで作成したブログのデータ一覧を取得するクエリです)。

export const pageQuery = graphql`
  query PagePosts {
    allMicrocmsPosts {
      edges {
        node {
          id
          postsId
          title
          day
          tags {
            id
            name
          }
          image {
            url
          }
        }
      }
    }
  }
`;


すると、

//graphql-types.ts
export type PagePostsQuery = { allMicrocmsPosts: { edges: Array<{ node: (
        Pick<MicrocmsPosts, 'id' | 'postsId' | 'title' | 'day'>
        & { tags?: Maybe<Array<Maybe<Pick<MicrocmsPostsTags, 'id' | 'name'>>>>, image?: Maybe<Pick<MicrocmsPostsImage, 'url'>> }
      ) }> } };



このようなクエリがビルド時に自動生成されます。これを用いて以下のようなコードを書いてみます。

//src/pages/posts.tsx
import * as React from 'react';
import { graphql, Link } from 'gatsby';
import { PagePostsQuery } from '../../graphql-types';

type Props = {
  data: PagePostsQuery;
};

const Posts: React.FC<Props> = ({ data }) => (
  <div>
    <h1>Post Page</h1>
    {data.allMicrocmsPosts?.edges?.map((edge) => {
      const posts = edge.node;
      return (
        <React.Fragment key={posts.id}>
          <div>
            <Link to={`/posts/${posts.postsId}`}>
              <h2>{posts.title}</h2>
            </Link>
            <div>
              {posts?.tags?.map(
                (tag) =>
                  tag?.id && (
                    <React.Fragment key={tag.id}>
                      <span>{tag.name}</span>
                    </React.Fragment>
                  ),
              )}
            </div>
            <p>{posts.day}</p>
            {posts?.image?.url && (
              <img src={posts.image.url} />
            )}
          </div>
        </React.Fragment>
      );
    })}
  </div>
);

export const pageQuery = graphql`
  query PagePosts {
    allMicrocmsPosts {
      edges {
        node {
          id
          postsId
          title
          day
          tags {
            id
            name
          }
          image {
            url
          }
        }
      }
    }
  }
`;

export default Posts;


コードをホバーすると以下の画像のように型が適用され、型安全なコードが実現されているのがわかります。
コードの例(ホバーされたコードに型定義が推論されている)
graphqlを使用する際にはoptional Chainingは必須です。画像のようにnull checkを行う場合には使用して簡潔なコードを書けるようにしましょう(もっと良い書き方あれば指摘お願いします)。
optional Chainingについては以下の記事がおすすめです。
そろそろJavaScriptに採用されそうなOptional Chainingを今さら徹底解説

動的なページを作成


元記事をご参照ください。
microCMSでブログデータの型を参照するには
MicrocmsPostsConnection, MicrocmsPosts という型を使用しました。

//graphql-types.ts
export type MicrocmsPosts = Node & {
  id: Scalars['ID'];
  parent?: Maybe<Node>;
  children: Array<Node>;
  internal: Internal;
  createdAt?: Maybe<Scalars['Date']>;
  updatedAt?: Maybe<Scalars['Date']>;
  title?: Maybe<Scalars['String']>;
  tags?: Maybe<Array<Maybe<MicrocmsPostsTags>>>;
  day?: Maybe<Scalars['Date']>;
  image?: Maybe<MicrocmsPostsImage>;
  content?: Maybe<Scalars['String']>;
  postsId?: Maybe<Scalars['String']>;
};

export type MicrocmsPostsConnection = {
  totalCount: Scalars['Int'];
  edges: Array<MicrocmsPostsEdge>;
  nodes: Array<MicrocmsPosts>;
  pageInfo: PageInfo;
  distinct: Array<Scalars['String']>;
  group: Array<MicrocmsPostsGroupConnection>;
};


良さげですね。graphql-codegenで生成される型定義はnull checkが厳格です(一長一短ですが)。
厳格にTypeScriptを導入してみたい方はお試しください。
あと単純に生成されるコードを読むと勉強になるかなあと思います。

まとめ

元記事がとても素晴らしいので、そちらも読んでください。良い記事をありがとうございます。
TypeScript導入の際にとても参考になりました。

ただ、null checkが厳格なので単純なブログサイトを作成するには少し工夫が必要かも知れません。
個人的には初期設定をすればあとはvsCodeでの自動補完、TypeScriptでの補完も聞くので開発体験は最高でした。
データの型も保障されますし。

サンプルコードは以下をご参照ください。
GitHub

参考記事