Closed7

@graphql-codegen/client-presetでData fragment maskingを試す

isingising

https://the-guild.dev/graphql/codegen/plugins/typescript/typescript-react-query
@graphql-codegen/typescript-react-queryプラグインでhookを生成しようと思ったが、ドキュメントを見るとclient-presetを推奨するとあったためこれを試す

We now recommend using the client-preset package for a better developer experience and smaller impact on bundle size.

https://the-guild.dev/graphql/codegen/docs/guides/react-vue
https://the-guild.dev/graphql/codegen/plugins/presets/preset-client
https://the-guild.dev/blog/unleash-the-power-of-fragments-with-graphql-codegen

isingising

client-presetが生まれた背景が以下のissueに書いてある

https://github.com/dotansimha/graphql-code-generator/issues/8296

既存の各種プラグイン(typescript-react-apollo、typescript-react-queryなど)はGraphQLクライアントをタイプセーフな方法でラップするフックやSDKの生成している。
これには以下の課題がある。

  • バンドルサイズの肥大化
  • 生成したフックシグネチャとGraphQLクライアントとのずれ
  • パッケージ間での構成オプションとプリセットの互換性の不整合

client-presetはすべてのGraphQLクライアント向けのプリセットで、バンドルサイズの縮小や型の強化が期待される。useQueryには生成したTypeDocumentNodeを渡す。
そしてRelayのようなFragment maskingをするためのAPI(useFragment)まで使える。

isingising

サンプルコード

import { FragmentType, useFragment } from './gql/fragment-masking'
import { graphql } from '../src/gql'

export const FilmFragment = graphql(/* GraphQL */ `
 fragment FilmItem on Film {
 id
 title
 releaseDate
 producers
 }
`)

const Film = (props: { film: FragmentType<typeof FilmFragment> }) => {
 const film = useFragment(FilmFragment, props.film)
 return (
 <div>
 <h3>{film.title}</h3>
 <p>{film.releaseDate}</p>
 </div>
 )
}

export default Film
isingising

graphqlクライアントはreact query (with graphql-request)

$ yarn add graphql react-query graphql-request
$ yarn add -D @graphql-codegen/cli @graphql-codegen/client-preset
// package.json
"scripts": {
    "codegen": "graphql-codegen --config codegen.ts"
  },
$ yarn codegen 
isingising

src/gql配下にコードが生成される

  • fragment-masking.ts
    • その名の通り。FragmentType型やuseFragmentが生成される
  • gql.ts
    • ここにTypedDocumentNodeが吐かれる。この段階ではまだない。
  • graphql.ts
    • ここにgraphqlスキーマから生成された型が吐かれる
  • index.ts
    • gql.tsとfragment-masking.tsを再エクスポートしてる

typescript-react-queryが生成するようなフックは生成されない

isingising

src/gql/gql.tsのgraphql関数を使ってGraphQLクエリやミューテーションを定義する

# Parent Component
const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ `
  query allFilmsWithVariablesQuery($first: Int!) {
    allFilms(first: $first) {
      edges {
        node {
          ...FilmItem
        }
      }
    }
  }
`)
# child component
export const FilmFragment = graphql(/* GraphQL */ `
  fragment FilmItem on Film {
    id
    title
    releaseDate
    producers
  }
`)

yarn codegenするとTypeDocumentNodeが生成されている

isingising

生成されたallFilmsWithVariablesQueryDocumentをreact-queryのuseQueryに渡す
仮にapolloやurqlに変えた場合でもuseQuery系のメソッドに同じようにDocumentを渡せばいい

# Parent Component
const { data } = useQuery(
    ['films'],
    async () =>
      await request(
        'https://swapi-graphql.netlify.app/.netlify/functions/index',
        allFilmsWithVariablesQueryDocument,
        {
          first: 10,
        }
      )
  )
このスクラップは2023/04/28にクローズされました