It is now easier than ever to migrate from Apollo Client generated hooks (by @graphql-codegen/typescript-react-apollo) to Client Preset with our brand new GraphQL codemod.

Why do you need to migrate?

Apollo Client v4 has a lot of interesting type overrides to serve as type-hint during development time. However, we lose these types by using the Apollo Client generated hooks. Client Preset was created to solve this issue (and the bloated bundle size caused by the generated hooks), so it remains our recommended approach to write GraphQL operations.

There are lots more benefits for using Client Preset:

  • Works with any GraphQL: Apollo Client, urql, GraphQL Request, and more.
  • Supports fragment masking: Components get exactly what they declare, no surprises.
  • Managed experience: Code more, configure less.

We have created a codemod @eddeee888/gcg-operation-location-migration to make the migration smoother.

Codemod usage

The codemod can be plugged easily into your Codegen config and run once during the migration.

How it works

Before

There are two main approaches to using a @graphql-codegen/typescript-react-apollo setup:

  • Index-based approach, where all hooks are generated into one file
  • Near-operation file approach, where hooks are generated into a file next to the consuming component

For example, given an operation document file like this:

# src/operations/User.graphql query User($id: ID!) { user(id: $id) { id name } }

A generated hook/s would be generated into an index or near-operation file:

// src/generated/types.ts export function useUserQuery( baseOptions: Apollo.QueryHookOptions<UserQuery, UserQueryVariables> & ({ variables: UserQueryVariables; skip?: boolean } | { skip: boolean }) ) { const options = { ...defaultOptions, ...baseOptions } return Apollo.useQuery<UserQuery, UserQueryVariables>(UserDocument, options) }

And, the hook is then used in a component file:

// src/User.tsx import { useUserQuery } from './generated/types' export const User = ({ id }) => { const { data } = useUserQuery({ variables: { id } }) // ... }

After

After running the codemod, your component file will be updated to support the Client Preset approach!

// src/User.tsx import { graphql } from './gql' const UserDoc = graphql(` query User($id: ID!) { user(id: $id) { id name } } `) export const User = ({ id }) => { const { data } = useQuery(UserDoc, { variables: { id } }) // ... }

You may see type errors if Client Preset is not fully set up by this point. Read on to see how the migration process works end-to-end.

How to run the codemod

Installation

npm install --save-dev @eddeee888/gcg-operation-location-migration

Updating Codegen config

Comment out all other Codegen generates blocks as they may interfere with the codemod, then add codemod config like the example below:

// codegen.ts import { defineConfig } from '@eddeee888/gcg-operation-location-migration' import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'src/**/*.graphqls', // 👈 This points to your usual GraphQL schema endpoint or files. documents: 'src/**/*.graphql', // 👈 This points to your operation files. generates: { /* * 💡 Example of index file generation approach * Once migrated, you can remove this completely */ // 'src/generated/types.ts': { // plugins: ['typescript', 'typescript-operations', 'typescript-react-apollo'], // }, /* * 💡 Example of near-operation file approach * Once migrated, you can remove this completely */ // 'src/graphql/types.ts': { // plugins: ['typescript'], // }, // './src/': { // preset: 'near-operation-file', // presetConfig: { // baseTypesPath: './graphql/types.ts', // extension: '.generated.ts', // }, // plugins: ['typescript-operations', 'typescript-react-apollo'], // }, // 💡 Codemod config example // `src/` is the base path where we want to run the codemod. 'src/': defineConfig({ tsConfigFilePath: './tsconfig.json', // 👈 Path from project root to your project tsconfig.json (Note: not from the base path). gqlTag: { name: 'graphql', // 👈 The tag used to parse operation documents. importFrom: './gql', // 👈 The the module to import the graphql tag. importType: 'relative' // 👈 Whether `importFrom` is relative or absolute. If relative, the path from the base path to the module. }, hooksImportFrom: '@apollo/client/react' // 👈 The module to import Apollo Client hooks. Use @apollo/client for older Apollo Client v3 versions. }) } } export default config

Running the codemod

Since the codemod is a Codegen preset, you can simply run Codegen to trigger it:

npm run codegen

If the codemod runs successfully, you should see your components file getting updated!

We have successfully tested the codemod on a few production repos with commonly used setup. If it does not work for your use case, please file an issue here: https://github.com/eddeee888/graphql-code-generator-plugins/issues

Setting up Client Preset

Now, you can make small changes to your Codegen config to be using Client Preset, then run Codegen again to wire up the migrated files!

// codegen.ts import type { CodegenConfig } from '@graphql-codegen/cli' const config: CodegenConfig = { schema: 'src/**/*.graphqls', documents: 'src/**/*.tsx', // 👈 Update this to point to your component files, where your operations have been migrated to. generates: { 'src/gql/': { preset: 'client' } } } export default config

Summary

In this blog post, we explored how to use GraphQL codemod to migrate from Apollo Client generated hooks approach to Client Preset. We hope this guide saves you time and reduces friction in your migration. Please reach out to @eddeee888 if you encounter any issues!

Last updated on