はじめに
個人開発にて GraphQL を採用しているのですが、schema を GraphQL Code Generator (以下 codegen と呼称)で管理しています。 typescript を前提にしています。
今までは type
のみを変換している程度でしたが、front 側(React.js を想定)で query
や mutation
を gql
タグで書くのを嫌って、それらも codegen で管理・変換したいという欲求が出てきました。
query
、mutation
なども codegen 側の管理責務であると捉えている- その方が見通しが良い
- gql タグで書かれた
qeury
などをどのファイルやディレクトリで管理するか迷うのが面倒
- フロント側で query 構文をミスった場合、debug に時間がかかる可能性がある
以下のような gql タグをわざわざフロント側で書きたくない!
1// hoge.tsx
2const fetchPosts = gql`
3 query fetchPost($slug: String!) {
4 post(slug: $slug) {
5 slug
6 title
7 description
8 category
9 tags
10 thumbnailUrl
11 body
12 createdAt
13 updatedAt
14 }
15 }
16`;
そこで、schema 上での query
、mutation
などの記述を TypeScript に変換してくれる typescript-graphql-request
という plugin が codegen では用意されています。
ちなみに codegen ではquery
、mutation
などを GraphQL documents と呼んでいるようです。
1# src/hoge.graphql
2query fetchPost($slug: String!) {
3 post(slug: $slug) {
4 slug
5 title
6 description
7 category
8 tags
9 thumbnailUrl
10 body
11 createdAt
12 updatedAt
13 }
14}
↓ 変換後
1// dist/hoge.ts
2
3const fetchPosts = gql`
4 query fetchPost($slug: String!) {
5 post(slug: $slug) {
6 slug
7 title
8 description
9 category
10 tags
11 thumbnailUrl
12 body
13 createdAt
14 updatedAt
15 }
16 }
17`;
やっと本題に入っていくのですが、
上述のように schema 上の documents を typescript-graphql-request
で .ts
に変換することで、フロントでわざわざ gql タグを書く必要がなくなるのですが、モノレポ構成で schema を単体の npm パッケージとして管理しているとこれだけでは不十分でした。
モノレポ構成が問題というよりは、schema 自体を単体のパッケージで管理しているのが問題で、別パッケージから const を呼び出そうとした際に .ts
では import できないので JavaScript にトランスパイルしてあげる必要があったのです。
なので、codegen で .graphql
から .ts
に変換して、tsc で .ts
から .js
に変換するようにしました。
設定例
1# ディレクトリ構成
2
3└── schema
4 ├── codegen.yml
5 ├── dist # 変換後のファイルが置かれる場所
6 │ ├── index.d.ts # `index.ts`をtscで変換
7 │ ├── index.js # `index.ts`をtscで変換
8 │ └── index.ts # codegenで変換された`.ts`
9 ├── package.json
10 ├── src # schemaファイルが置かれる場所
11 │ ├── main.gql
12 │ └── hoge.gql
13 └─── tsconfig.json # トランスパイルする関係で必要
1# codegen.yml
2schema: src/**/*.gql
3
4generates:
5 dist/index.ts: # tsに変換している
6 documents: src/**/*.gql # GraphQL documentsが記述されているファイルを指定する
7 plugins:
8 - typescript
9 - typescript-operations
10 - typescript-graphql-request
1// tsconfig.json
2// schemaの型も読むために、`declaration`をtrueにしておくぐらいです
3{
4 "include": ["dist/index.ts"],
5 "exclude": ["node_modules"],
6 "compilerOptions": {
7 "target": "es5",
8 "module": "commonjs",
9 "declaration": true /* Generates corresponding '.d.ts' file. */,
10 "outDir": "./dist",
11 "strict": true,
12 "baseUrl": "./",
13 "paths": {
14 "*": ["node_modules/@types/*"]
15 }
16 }
17}
1// package.json
2// scriptsのみを抜粋
3// npm-run-allで`buld:*`を上から順に実行しています
4// graphql-codegenした後にtscしているだけです
5{
6 "scripts": {
7 "build": "npm-run-all build:*",
8 "build:clean": "rimraf dist",
9 "build:generate": "graphql-codegen --config codegen.yml",
10 "build:transpile": "tsc"
11 }
12}
おわりに
これって codegen 側で .js
までトランスパイルを一気にできないのですかね...?