🐚

graphql-codegen を Next.js の CSR と SSR/SG で使う際の知見

2021/12/07に公開

動機

graphql-codgen という、GraphQL のスキーマから型とかSDKを自動生成してくれるライブラリがとても便利なので個人開発で愛用しています。ただ案外、Next.jsSSR/SGで利用する記事があまり見当たらなかったので記事にしてみることにしました。

graphql-codegenについて

graphql-codgenは、冒頭でも述べた通り、GraphQLのスキーマ(ex. schema.graphql)から型とかSDKを自動生成してくれるライブラリです。GraphQLを使う以上は入れない理由が特にないかな、というくらい便利な代物なので是非導入してください。導入・使用の手順は概ね以下の通りです。

  1. graphql-codegenと周辺プラグインのインストール(yarn/npm)
  2. $ yarn graphql-codegen initで初期設定(任意)
  3. 設定ファイルの編集(ex. codegen.yml)
  4. フロント側でのQueryMutationの記述
  5. コマンドで型やSDKの自動生成

また、CSRSSR/SG共通で必要なライブラリやプラグインは以下です。(typescriptは使っている前提)

CSR

CSR(クライアントサイドレンダリング)でのgraphql-codegenに関しては、他にも記事がいくつか出ていますが一応書きます。Next.jsとはいえ実質CSRReactなので、React用のプラグインを導入します。

apolloGraphQL関連のライブラリ等を提供してくれているプラットフォームです。ここでは、データフェッチのための、@apollo/clientをインストールします。

以下のように、App.tsxをラップして、クライアントを設定することで共通化します。

_app.tsx
const client = new ApolloClient({
  uri: 'YOUR_GRAPHQL_SERVER',
  cache: new InMemoryCache()
});

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <ApolloProvider client={client}>
        <Component {...pageProps} />
      </ApolloProvider>
    </>
  )
}

export default MyApp

では、次にcodegen.ymlを記述して、自動生成の準備をしましょう。CSRの段階での、codegen.ymlは以下のようになりました。

config.yml
overwrite: true
schema: "YOUR_GRAPHQL_SCHEMA"
documents: "src/graphql/**/*.graphql"
generates:
  src/graphql/types.ts:
    plugins:
      - "typescript"
  src/graphql/:
    preset: near-operation-file
    presetConfig:
      extension: .generated.tsx
      baseTypesPath: types.ts
    plugins:
      - "typescript-operations"
      - "typescript-react-apollo"

near-operation-fileを導入している理由については以下の記事を参照。(パフォーマンスの問題です。)
https://blog.hiroppy.me/entry/2021/08/12/092839

では、取得したいデータのQueryMutationを書いたファイルを作りましょう。サンプルは長くなってしまったので以下アコーディオンに。

GraphQL例

https://github.com/lucasbento/graphql-pokemon を使ってみました。

getPikachu.graphql
query getPikachu {
  pokemon(name: "Pikachu") {
    id
    number
    name
    attacks {
      special {
        name
        type
        damage
      }
    }
    evolutions {
      id
      number
      name
      weight {
        minimum
        maximum
      }
      attacks {
        fast {
          name
          type
          damage
        }
      }
    }
  }
}

ここまでできたら、以下のコマンドを叩けば、自動生成ファイルが作成されるはずです。

$ yarn codegen

あとは、各ページやコンポーネントで使用しましょう!

使用例
const Pikachu: NextPage = () => {
  const { loading, error, data } = useGetPikachuQuery();
  if (loading) {
    return <></>
  }
  if (!data?.pokemon) {
    return <></>
  }
  return (
    <>
      <h1>{ data.pokemon.name }</h1>
    </>
  )
}

export default Pikachu

SSR/SG

では、本題のSSR(サーバーサイドレンダリング)やSG(スタティックジェネレーション)での使用方法です。個人的にはSGを圧倒的に推しているので、そちらでの使用方法を例にします。(ただし、基本的には同じです。)

SSR/SGでは、graphql-requestというシンプルなクライアントを利用することを想定して、以下のプラグインとプリセットを導入します。

codegen.ymlに以下の記述を追加します。

config.yml
overwrite: true
schema: "YOUR_GRAPHQL_SCHEMA"
documents: "src/graphql/**/*.graphql"
generates:
  src/graphql/types.ts:
    plugins:
      - "typescript"
  src/graphql/:
    (...)
+  src/graphql/ssr.generated.ts:
+    preset: import-types
+    presetConfig:
+      typesPath: "./types"
+    plugins:
+      - "typescript-operations"
+      - "typescript-graphql-request"

あとは、$ yarn codegenで自動生成して使用することができます。

使用例
const Pikachu: NextPage<GetPikachuQuery> = (props) => {
  if (!props?.pokemon) {
    return <><h1>Pikachu Not Found</h1></>
  }
  return (
    <>
      <h1>{ props.pokemon.name }</h1>
    </>
  )
}

export async function getStaticProps() {
  const client = new GraphQLClient('YOUR_GRAPHQL_SERVER')
  const sdk = getSdk(client)
  const { pokemon } = await sdk.getPikachu() 
  return {
    props: {
      pokemon: pokemon,
    },
  }
}

export default Pikachu

まとめ

graphql-codegenを使って良いGraphQLライフを!

参考

https://zenn.dev/mikan3rd/articles/5b7840cdbcd2d9
そもそもGraphQLを使って、個人開発を始めたきっかけになった記事です。とても参考になります。

https://blog.hiroppy.me/entry/2021/08/12/092839
この記事を書いている際に見つけたのですが、Next.js@graphql-codegen/typescript-react-apolloを使う際にはパフォーマンスの問題にも気を使う必要があるようです。

https://zenn.dev/tak_iwamoto/articles/44a61021d7d251
SSRApolloを使う場合に起きるオーバーヘッドについてです。SGでは、さほど問題とならないかもしれませんが、今回は念の為別のクライアントを使いました。

https://github.com/lucasbento/graphql-pokemon
ポケモンのデータを取得できるGraphQLサーバーです。勉強や実験に使えます。

株式会社ゆめみ

Discussion