Files
2026-07-13 21:36:20 +08:00

8.2 KiB
Raw Permalink Blame History

name, description, metadata
name description metadata
tooling 用于处理 GraphQL 操作的工具参考,包括代码生成与代码检查
type
reference

工具

本参考文档涵盖了用于处理 GraphQL 操作的工具,包括代码生成和代码检查。

目录

GraphQL 代码生成器

概述

GraphQL 代码生成器可从你的 schema 和操作中生成 TypeScript 类型,确保整个应用程序的类型安全。

安装

npm install -D @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typed-document-node

基本配置

创建 codegen.ts

// codegen.ts
import { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
  overwrite: true,
  schema: "<URL_OF_YOUR_GRAPHQL_API>",
  // 假设所有源文件都在顶层的 `src/` 目录下——你可能需要根据你的文件结构调整此项
  documents: ["src/**/*.{ts,tsx}"],
  // 当没有文档时不以非零状态退出
  ignoreNoDocuments: true,
  generates: {
    // 使用最适合你应用程序结构的路径
    "./src/types/__generated__/graphql.ts": {
      plugins: ["typescript", "typescript-operations", "typed-document-node"],
      config: {
        avoidOptionals: {
          // 对可空字段使用 `null` 而非可选字段
          field: true,
          // 允许可空输入字段保持未指定状态
          inputValue: false,
        },
        // 对未配置的标量使用 `unknown` 而非 `any`
        defaultScalarType: "unknown",
        // Apollo Client 始终包含 `__typename` 字段
        nonOptionalTypename: true,
        // Apollo Client 不会为根类型添加 `__typename` 字段,因此
        // 不要为根操作类型生成 `__typename` 的类型。
        skipTypeNameForRoot: true,
      },
    },
  },
};

export default config;

运行生成

# 一次性生成
npx graphql-codegen

# 开发时的监听模式
npx graphql-codegen --watch

Package 脚本

{
  "scripts": {
    "codegen": "graphql-codegen",
    "codegen:watch": "graphql-codegen --watch"
  }
}

生成类型的使用

// 之前:手动类型定义
const GET_USER = gql`
  query GetUser($id: ID!) {
    user(id: $id) {
      id
      name
    }
  }
`;

// 手动类型定义
interface GetUserData {
  user: {
    id: string;
    name: string;
  } | null;
}

const { data } = useQuery<GetUserData>(GET_USER, { variables: { id } });

// 之后:使用生成类型
import { useGetUserQuery } from "./generated/graphql";

const { data } = useGetUserQuery({ variables: { id } });
// data.user 现在是完整类型化的!

近操作文件生成

在操作文件旁边生成类型:

const config: CodegenConfig = {
  schema: "http://localhost:4000/graphql",
  documents: ["src/**/*.graphql"],
  generates: {
    "src/": {
      preset: "near-operation-file",
      presetConfig: {
        extension: ".generated.ts",
        baseTypesPath: "generated/graphql.ts",
      },
      plugins: ["typescript-operations", "typescript-react-apollo"],
    },
    "src/generated/graphql.ts": {
      plugins: ["typescript"],
    },
  },
};

结果如下:

src/
  components/
    UserCard/
      UserCard.graphql
      UserCard.generated.ts  # 该文件的生成类型

片段类型

// UserAvatar.graphql
// fragment UserAvatar on User {
//   id
//   name
//   avatarUrl
// }

import { UserAvatarFragment } from "./UserAvatar.generated";

interface UserAvatarProps {
  user: UserAvatarFragment;
}

export function UserAvatar({ user }: UserAvatarProps) {
  return <img src={user.avatarUrl} alt={user.name} />;
}

ESLint GraphQL

安装

npm install -D @graphql-eslint/eslint-plugin

配置

// eslint.config.js(扁平配置)
import graphqlPlugin from "@graphql-eslint/eslint-plugin";

export default [
  {
    files: ["**/*.graphql"],
    languageOptions: {
      parser: graphqlPlugin.parser,
    },
    plugins: {
      "@graphql-eslint": graphqlPlugin,
    },
    rules: {
      "@graphql-eslint/known-type-names": "error",
      "@graphql-eslint/no-anonymous-operations": "error",
      "@graphql-eslint/no-duplicate-fields": "error",
      "@graphql-eslint/naming-convention": [
        "error",
        {
          OperationDefinition: {
            style: "PascalCase",
            forbiddenPrefixes: ["Query", "Mutation", "Subscription"],
          },
          FragmentDefinition: {
            style: "PascalCase",
          },
        },
      ],
    },
  },
];

推荐规则

rules: {
  // 语法与合法性
  '@graphql-eslint/known-type-names': 'error',
  '@graphql-eslint/known-fragment-names': 'error',
  '@graphql-eslint/no-undefined-variables': 'error',
  '@graphql-eslint/no-unused-variables': 'error',
  '@graphql-eslint/no-unused-fragments': 'error',
  '@graphql-eslint/unique-operation-name': 'error',
  '@graphql-eslint/unique-fragment-name': 'error',

  // 最佳实践
  '@graphql-eslint/no-anonymous-operations': 'error',
  '@graphql-eslint/no-duplicate-fields': 'error',
  '@graphql-eslint/require-id-when-available': 'warn',

  // 命名规范
  '@graphql-eslint/naming-convention': ['error', { ... }],
}

Schema 感知规则

提供 schema 以实现高级验证:

{
  files: ['**/*.graphql'],
  languageOptions: {
    parser: graphqlPlugin.parser,
    parserOptions: {
      schema: './schema.graphql',
      // 或者
      schema: 'http://localhost:4000/graphql',
    },
  },
}

IDE 扩展

VS Code

GraphQL:语言功能支持GraphQL 基金会)

  • 语法高亮
  • Schema 类型的自动补全
  • 跳转到定义
  • 悬停文档
  • 针对 schema 的验证

配置(.graphqlrc.yml):

schema: "http://localhost:4000/graphql"
documents: "src/**/*.{graphql,ts,tsx}"

Apollo GraphQLApollo

  • Apollo 特有功能
  • Schema 注册表集成
  • 性能洞察

JetBrains IDE

GraphQL 插件:

  • 语法高亮
  • Schema 感知的补全
  • 验证
  • 导航到定义

配置(.graphqlconfig):

{
  "schemaPath": "./schema.graphql",
  "includes": ["src/**/*.graphql"]
}

配置文件

常见的配置文件名:

  • .graphqlrcJSON
  • .graphqlrc.ymlYAML
  • .graphqlrc.jsonJSON
  • graphql.config.jsJavaScript
# .graphqlrc.yml
schema: "http://localhost:4000/graphql"
documents: "src/**/*.graphql"
extensions:
  codegen:
    generates:
      ./src/generated/graphql.ts:
        plugins:
          - typescript
          - typescript-operations

操作验证

针对 Schema 进行验证

# 使用 graphql-inspector
npx graphql-inspector validate ./src/**/*.graphql ./schema.graphql

CI 集成

# .github/workflows/graphql.yml
name: GraphQL 验证

on: [push, pull_request]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: 安装依赖
        run: npm ci

      - name: 下载 schema
        run: npx graphql-inspector introspect http://localhost:4000/graphql --write schema.graphql

      - name: 验证操作
        run: npx graphql-inspector validate './src/**/*.graphql' schema.graphql

      - name: 检查破坏性变更
        run: npx graphql-inspector diff schema.graphql http://localhost:4000/graphql

Pre-commit 钩子

// package.json
{
  "lint-staged": {
    "*.graphql": ["eslint --fix", "graphql-inspector validate ./schema.graphql"]
  }
}

操作复杂度检查

# 检查查询复杂度
npx graphql-query-complexity-checker \
  --schema ./schema.graphql \
  --query ./src/queries/GetUser.graphql \
  --max-complexity 100

持久化查询提取

生成用于生产环境的持久化查询:

// codegen.ts
const config: CodegenConfig = {
  generates: {
    "./persisted-queries.json": {
      plugins: ["graphql-codegen-persisted-query-ids"],
      config: {
        output: "client",
        algorithm: "sha256",
      },
    },
  },
};

输出:

{
  "abc123...": "query GetUser($id: ID!) { user(id: $id) { id name } }",
  "def456...": "mutation CreatePost($input: CreatePostInput!) { ... }"
}