graphql-codegen を Next.js の CSR と SSR/SG で使う際の知見
動機
graphql-codgen という、GraphQL のスキーマから型とかSDKを自動生成してくれるライブラリがとても便利なので個人開発で愛用しています。ただ案外、Next.jsのSSR/SGで利用する記事があまり見当たらなかったので記事にしてみることにしました。
graphql-codegenについて
graphql-codgenは、冒頭でも述べた通り、GraphQLのスキーマ(ex. schema.graphql)から型とかSDKを自動生成してくれるライブラリです。GraphQLを使う以上は入れない理由が特にないかな、というくらい便利な代物なので是非導入してください。導入・使用の手順は概ね以下の通りです。
-
graphql-codegenと周辺プラグインのインストール(yarn/npm) -
$ yarn graphql-codegen initで初期設定(任意) - 設定ファイルの編集(ex.
codegen.yml) - フロント側での
QueryやMutationの記述 - コマンドで型や
SDKの自動生成
また、CSR、SSR/SG共通で必要なライブラリやプラグインは以下です。(typescriptは使っている前提)
- graphql
- @graphql-codegen/cli
- @graphql-codegen/typescript
- @graphql-codegen/typescript-operations
- @graphql-codegen/near-operation-file-preset
CSR
CSR(クライアントサイドレンダリング)でのgraphql-codegenに関しては、他にも記事がいくつか出ていますが一応書きます。Next.jsとはいえ実質CSRはReactなので、React用のプラグインを導入します。
apolloはGraphQL関連のライブラリ等を提供してくれているプラットフォームです。ここでは、データフェッチのための、@apollo/clientをインストールします。
以下のように、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は以下のようになりました。
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を導入している理由については以下の記事を参照。(パフォーマンスの問題です。)
では、取得したいデータのQueryやMutationを書いたファイルを作りましょう。サンプルは長くなってしまったので以下アコーディオンに。
GraphQL例
https://github.com/lucasbento/graphql-pokemon を使ってみました。
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に以下の記述を追加します。
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ライフを!
参考
そもそもGraphQLを使って、個人開発を始めたきっかけになった記事です。とても参考になります。
この記事を書いている際に見つけたのですが、Next.jsで@graphql-codegen/typescript-react-apolloを使う際にはパフォーマンスの問題にも気を使う必要があるようです。
SSRでApolloを使う場合に起きるオーバーヘッドについてです。SGでは、さほど問題とならないかもしれませんが、今回は念の為別のクライアントを使いました。
ポケモンのデータを取得できるGraphQLサーバーです。勉強や実験に使えます。
Discussion