关于 graphql-codegen
面向 TypeScript 开发者的 GraphQL Code Generator 参考技能,涵盖配置、生成类型及客户端集成。适用于从 GraphQL schema 和操作文档生成类型安全代码的项目。
主要功能
- 01CLI 配置与代码生成
- 02客户端预设与类型生成
- 03TanStack Query 集成
- 04片段共置
- 05多 schema 配置
- 06CI 与监视模式
适用场景
- 01从 schema 和操作文档生成 TypeScript 代码
- 02为 GraphQL 操作生成客户端查询钩子
- 03在开发期间监视文档并重新生成
MCP 相关
提及可通过 `mcp__documentation__fetch_docs` 获取 graphql-codegen 的深入文档。
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ claude-dev-suite/ claude-dev-suite --skill graphql-codegen安装后在 Claude Code 中输入/graphql-codegen确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
quick-ref/client-preset.mdreact-query.mdtyped-document-node.md详细介绍
GraphQL Code Generator 核心知识
深度知识:使用
mcp__documentation__fetch_docs,并将技术设为graphql-codegen,获取完整文档。
安装
npm install -D @graphql-codegen/cli @graphql-codegen/typescript \
@graphql-codegen/typescript-operations @graphql-codegen/client-preset
基本配置
// codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli';
const config: CodegenConfig = {
schema: 'http://localhost:4000/graphql',
documents: ['src/**/*.tsx', 'src/**/*.ts'],
ignoreNoDocuments: true,
generates: {
'./src/gql/': {
preset: 'client',
config: {
documentMode: 'string',
},
},
},
};
export default config;
运行生成
npx graphql-codegen
npx graphql-codegen --watch # Watch mode
Client Preset(推荐)
client preset 会生成实现 GraphQL 类型安全所需的一切内容。
// codegen.ts
const config: CodegenConfig = {
schema: 'http://localhost:4000/graphql',
documents: ['src/**/*.tsx'],
generates: {
'./src/gql/': {
preset: 'client',
plugins: [],
presetConfig: {
gqlTagName: 'gql',
fragmentMasking: { unmaskFunctionName: 'getFragmentData' },
},
},
},
};
用法
import { gql } from '../gql';
import { useQuery } from '@apollo/client';
const GET_USER = gql(`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`);
function UserProfile({ id }: { id: string }) {
const { data, loading } = useQuery(GET_USER, {
variables: { id },
});
if (loading) return <Spinner />;
// data.user is fully typed
return <div>{data?.user?.name}</div>;
}
TanStack Query 集成
npm install -D @graphql-codegen/typescript-react-query
// codegen.ts
const config: CodegenConfig = {
schema: 'http://localhost:4000/graphql',
documents: ['src/**/*.graphql'],
generates: {
'./src/gql/index.ts': {
plugins: [
'typescript',
'typescript-operations',
'typescript-react-query',
],
config: {
fetcher: {
func: './fetcher#fetcher',
isReactHook: false,
},
reactQueryVersion: 5,
addInfiniteQuery: true,
},
},
},
};
Fetcher
// src/gql/fetcher.ts
export const fetcher = <TData, TVariables>(
query: string,
variables?: TVariables
): (() => Promise<TData>) => {
return async () => {
const response = await fetch('http://localhost:4000/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${getToken()}`,
},
body: JSON.stringify({ query, variables }),
});
const json = await response.json();
if (json.errors) {
throw new Error(json.errors[0].message);
}
return json.data;
};
};
生成的 Hooks 用法
import { useGetUserQuery, useCreateUserMutation } from './gql';
function UserProfile({ id }: { id: string }) {
const { data, isLoading } = useGetUserQuery({ id });
const createMutation = useCreateUserMutation();
const handleCreate = () => {
createMutation.mutate({
input: { name: 'John', email: '[email protected]' },
});
};
if (isLoading) return <Spinner />;
return <div>{data?.user?.name}</div>;
}
片段就近放置
// components/UserAvatar.tsx
import { gql, FragmentType, getFragmentData } from '../gql';
export const USER_AVATAR_FRAGMENT = gql(`
fragment UserAvatar on User {
id
name
avatarUrl
}
`);
interface Props {
user: FragmentType<typeof USER_AVATAR_FRAGMENT>;
}
export function UserAvatar({ user }: Props) {
const data = getFragmentData(USER_AVATAR_FRAGMENT, user);
return <img src={data.avatarUrl} alt={data.name} />;
}
// Usage in parent query
const GET_USER = gql(`
query GetUser($id: ID!) {
user(id: $id) {
id
...UserAvatar
}
}
`);
生产就绪
Schema 轮询
// codegen.ts
const config: CodegenConfig = {
schema: [
{
'http://localhost:4000/graphql': {
headers: {
Authorization: `Bearer ${process.env.GRAPHQL_TOKEN}`,
},
},
},
],
// ...
};
多个 Schema
const config: CodegenConfig = {
generates: {
'./src/gql/user-api/': {
schema: 'http://user-api:4000/graphql',
documents: ['src/features/user/**/*.tsx'],
preset: 'client',
},
'./src/gql/product-api/': {
schema: 'http://product-api:4001/graphql',
documents: ['src/features/product/**/*.tsx'],
preset: 'client',
},
},
};
CI/CD 集成
# .github/workflows/codegen.yml
name: GraphQL Codegen
on:
push:
paths:
- 'src/**/*.graphql'
- 'src/**/*.tsx'
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx graphql-codegen
- name: Check for changes
run: |
if [[ -n $(git status --porcelain src/gql) ]]; then
echo "Generated files changed"
exit 1
fi
Package 脚本
{
"scripts": {
"codegen": "graphql-codegen",
"codegen:watch": "graphql-codegen --watch"
}
}
检查清单
- 已配置 Schema 来源(URL 或本地)
- Documents 路径与源文件相匹配
- 使用 client preset 以获得最佳输出
- 已配置带身份验证的 Fetcher
- 采用片段就近放置模式
- 开发时启用监视模式
- CI 中验证生成的代码
- 兼容 TypeScript strict 模式
不适用此技能的情况
- REST API 类型生成(使用
openapi-codegen技能) - tRPC 类型安全 API(使用
trpc技能) - GraphQL Schema 设计(使用
graphql技能) - 非 TypeScript 项目
- 无需生成类型的简单 GraphQL 查询
反模式
| 反模式 | 为什么不好 | 解决方案 |
|---|---|---|
| 将生成的文件提交到 git | 合并冲突、类型过时 | 添加到 .gitignore,并在 CI 中生成 |
| 不使用 client preset | 配置冗长 | 使用 client preset 进行现代化配置 |
| 忽略 Schema 变更 | 运行时类型不匹配 | 开发期间以监视模式运行 codegen |
| 缺少 operationId 或查询名称 | 生成的 hook 名称不佳 | 为所有查询/变更命名 |
| 不使用片段 | 代码重复 | 使用片段复用字段 |
| 只生成类型 | 缺少运行时验证 | 与 Schema 验证结合使用 |
| 将 Schema URL 写死 | 与环境耦合 | 使用环境变量指定 Schema 来源 |
| 不对生成器包进行版本固定 | 团队成员生成的输出不一致 | 固定生成器版本 |
快速故障排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 生成失败 | Schema 或 Documents 无效 | 验证 Schema,检查 GraphQL 语法 |
| 生成后出现类型错误 | Schema/代码不匹配 | 重新生成类型,检查 Schema 变更 |
| 缺少类型 | Documents 路径与文件不匹配 | 检查 Documents glob 模式 |
| 操作名称重复 | 多个文件中存在同名查询 | 使用唯一的操作名称 |
| 找不到片段 | Documents 中不包含该片段 | 将片段文件加入 Documents |
| 未生成 Hook | 未使用 React Query 插件 | 添加 typescript-react-query 插件 |
| "Cannot find module './gql'" | 未运行生成 | 运行 npm run codegen |
| 生成缓慢 | Documents 过多 | 优化 glob 模式,使用 ignoreNoDocuments |
| 类型推断不起作用 | 导入路径错误 | 从生成的 gql 文件夹导入 |
参考文档
评论
支持 Markdown