サイトアイコン

toLog

graphql-codegenで変換したtsをさらにトランスパイルする

  • 更新日:
  • 投稿日:
サムネイル

この記事は最終更新日から2年以上が経過しています。

はじめに

個人開発にて GraphQL を採用しているのですが、schema を GraphQL Code Generator (以下 codegen と呼称)で管理しています。 typescript を前提にしています。

今までは type のみを変換している程度でしたが、front 側(React.js を想定)で querymutationgql タグで書くのを嫌って、それらも codegen で管理・変換したいという欲求が出てきました。

  • querymutation なども 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 上での querymutation などの記述を TypeScript に変換してくれる typescript-graphql-request という plugin が codegen では用意されています。 ちなみに codegen ではquerymutationなどを 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までトランスパイルを一気にできないのですかね...?


プロフィール画像

canji

とにかく私的にサービスを作りたい発作を起こしている。お腹はペコペコ。

  • toLog Tools icon
  • dots icon