行き詰まった経緯
graphql
の練習としてフロントエンドでcodegen
を使用して自動的にコード生成をしようとしていた。
以前も使用したことはあったので多少は設定に困らなかったが、今回はhooksも自動生成しようと思って、設定内容を変えてみた。
実装の概略は次章で説明する。
問題となったエラーは以下の通り
the name `GetUsersDocument` is defined multiple times
実装
codegenをinstall
pnpm i -D graphql @graphql-codegen/cli
codegen
の初期化
pnpm grapql-codegen init
対話形式で初期化が始まる(今回はNextjsのプロジェクトであるためReactを選択)
? What type of application are you building? (Use arrow keys)
Backend - API or server
Application built with Angular
❯ Application built with React
Application built with Stencil
Application built with Vue
Application using graphql-request
Application built with other framework or vanilla JS
schema
の場所の指定(今回はlocalhost:8080
にgraphqlサーバーが立っている)
? Where is your schema?: (path or url) http://localhost:8080/v1/graphql
graphql
ドキュメントを読み込むパスの指定
? Where are your operations and fragments?:src/graphql/**/*.graphql
生成されたコードをどこに出力するかの設定(今回はsrc/generates/
)
? Where to write the output: src/generates/
introspection file
を作るかどうか (今回はyes)
? Do you want to generate an introspection file? (y/N)
コンフィグファイルの名前(今回はデフォルト)
? How to name the config file? (codegen.ts)
npmコマンドの名前(これもデフォルト)
? What script in package.json should run the codegen? (codegen)
対話終了
Fetching latest versions of selected plugins...
Config file generated at codegen.ts
$ npm install
To install the plugins.
$ npm run codegen
To run GraphQL Code Generator.
npm install
をしてねって言われてるので
pnpm install
を実行
試しにクエリドキュメント作成
query GetUsers {
users {
id
userName
}
}
データベースにはid
とuserName
のcolumnを持つusers
テーブル
codegen
を実行するときは
npm run codegen
を使ってねって言われてるので
pnpm codegen
を実行
構造は以下の通り
src
├── generates
│ ├── fragment-masking.ts
│ ├── gql.ts
│ ├── graphql.ts
│ └── index.ts
├── graphql
│ └── query
│ └── getUser.graphql
ここまでで単純なgraphqlのコード生成は終了
本題
今回の目標はhooks
を生成すること
必要なライブラリをインストール
npm i -D @graphql-codegen/typescript @graphql-codegen/typescript-react-apollo @graphql-codegen/typescript-operations @apollo/client
codegen.ts
を次のように編集
import type { CodegenConfig } from "@graphql-codegen/cli";
const config: CodegenConfig = {
overwrite: true,
schema: "http://localhost:8080/v1/graphql",
documents: "src/graphql/**/*.graphql",
generates: {
"src/generates/": {
preset: "client",
plugins: [
"typescript",
"typescript-operations",
"typescript-react-apollo",
],
config: {
skipTypename: false,
withHOC: true,
withComponent: false,
scalars: {
uniqueidentifier: "string",
},
},
},
"./graphql.schema.json": {
plugins: ["introspection"],
},
},
};
export default config;
plugins
で使用するpluginを設定
config
で生成されるコードの詳細を設定できる
諸々を省くが実際にクエリを叩いたところ以下エラーが出力された
./src/generates/graphql.ts
NonErrorEmittedError: (Emitted value instead of an instance of Error)
x the name `GetUsersDocument` is defined multiple times
エラーの内容としてはgraphql.tsファイル内でGetUserDocument
が複数宣言されていることだった
codegen.ts
を以下のように編集するとエラーは改善された
generates: {
"src/generates/graphql.ts": { //出力先の変更
//presetを削除
plugins: [
"typescript",
"typescript-operations",
"typescript-react-apollo",
],
config: {
skipTypename: false,
withHOC: false,
withComponent: false,//出力するファイルを一つに設定する
scalars: {
uniqueidentifier: "string",
},
},
},
"./graphql.schema.json": {
plugins: ["introspection"],
},
},
どうやらpreset:"client"
が悪さをしていたみたい
そもそもpreset
とはなんなのか
公式ドキュメントによると
generates.preset - A list of presets to use for the output. Presets are a way to dynamically create the list of output files based on the input schema. near-operation-file-preset is a good example
とされている
codegen
で生成されるコードとpreset
で生成されたコードが重複してエラーが出力されていた感じなのだろうか(ちゃんと理解できてない分野であるため下手なことが言えない)
hooksを出力するメリット
なぜ今回出力先をhooksにしたのかについて
withHooks:true
にせずにデフォルトで使用する場合データを取得するクエリは以下のように書く必要がある(本記事ではcodegen
を主に取り扱っているためapollo client
に関して説明はしない)
const getUsersDoc = gql`
query GetUsers {
users {
id
userName
}
}
`
const {data} = useQuery(getUserDoc)
しかし設定を適用すると
query GetUsers {
users {
id
userName
}
}
const { data } = useGetUsersQuery();
といった感じでクエリと関数を別ファイルに分けることができる上に関数の命名がドキュメントに基づいた名前になるため直感的にわかりやすいと感じた。
hooks
出力にしなくてもドキュメントは別ファイルに分けることはできると言われればそれはそうとしか返せない。
関数名が変わるのが私個人としてはわかりやすくていいかなあといった感じだった。
そこもドキュメントの名前見ればわかるだろうと言われればそれもそうなのかもしれない
その他ここは違うなどの意見がございましたら教えていただけると幸いです。
参考