Graphql Codegen - 自动生成 TS 类型

引言

个人项目 《仿 Mac 个人网站开发 |项目复盘》 很早之前就用上了 Graphql, 近期对前端项目整体做了升级(转 NextJS、引入 react-query)! 在翻代码时看到之前配置的 Graphql Codegen 然后就是一脸懵逼(时间太久了, 都忘记每项配置的作用了...), 所以就重新查阅了下官网, 对这一块配置也进行了升级, 整个流程又重新走了一遍! 故而就有了本篇文章!!

项目源码: github.com/KunLunXu-CC...

一、什么是 Graphql Codegen

首先 Graphql Codegen 是一个 开发/构建 工具, 它主要的作用其实就是帮助我们自动生成 TS 类型

具体的来讲就是, 假设你的后端是 Graphql 服务, 并且在前端你是通过常规编写 Graphql 方式来调用接口的, 那么通过 Graphql Codegen 能够帮助你减少大量工作, 该工具可以监听 Graphql 操作, 并根据指定的 Graphql 服务, 生成所有必备的接口响应、请求参数等一些列 TS 类型, 甚至可以帮助你快速生成 useQuery 或 useMutation 等 hooks!!

有了它可以大大减少您必须编写的样板代码, 使得使用 GraphQL API 变得更加容易, 便捷! 并且通过简单的配置, 可以让 TS 的发挥最大化(智能提示)

二、配置讲解

其实官方已经提供了很 详细的文档, 本文只是做了些适当的简化、和说明, 所以在整个过程中, 如果遇到任何问题, 请以 官方 为准!!!!

2.1 基础配置

  1. 安装 @graphql-codegen/cli 依赖: 提供生成代码所必要的一些 CLI 工具
sh 复制代码
pnpm add --save-dev @graphql-codegen/cli
  1. 项目 根目录 下创建配置文件 codegen.ts
ts 复制代码
import type { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
  schema: "http://localhost:4000/api/graphql",
  documents: ["src/**/*.tsx"],
  ignoreNoDocuments: true,
  generates: {
    "./src/graphql/": {
      preset: "client",
      config: {
        documentMode: "string",
      },
    },
  },
};

export default config;

配置项说明:

  • schema: xxxx 用于指定后端 Graphql 服务地址, 我这边 后端服务 地址为 http://localhost:4000/api/graphql
  • documents 指定当前 前端 项目中可能包含 Graphql 操作的文件, 这个文件中如果匹配到 Graphql 操作代码, 则会自动生成我们预期的 TS 类型代码
  • generates 定义要生成的内容, 该配置是一个对象, 对象的 key 是生成内容文件对应的路径(可以是具体的文件、也可以是个目录), 而值则是生成的配置项(规定如果生成代码、生成怎么样的代码), 这里的配置和 Babel 有点像, 都是可以指定 preset、plugins 等内容
  • 更多配置内容参考: docs/config-reference/codegen-config

2.2 测试效果

是的没错, Graphql Codegen 配置很简单, 就简单的两步即可, 下面我们来看下它的效果(作用)!

  1. 随便找个地方, 写个页面(我这里是 NextJS 项目)
ts 复制代码
"use client";

const Demo = () => {
  return <div>11111</div>;
};

export default Demo;
  1. 下面问题来了, Graphql Codegen 是如何识别出文件中包含的 Graphql 操作代码呢? 其实就是通过一些特定的标识、写法、文件名, 来识别的。下面是我所知道的几种写法
  • 调用函数 graphql 或 gql, 其参数 字符串 会被视为 Graphql 操作代码, 即便函数没有定义(因为并没执行代码, 无所谓有没定义)
ts 复制代码
// graphql 函数的字符串参数会被视为 Graphql 操作代码, 被识别到
const getUserInfo = graphql(`
  query getUserInfo {
    userInfo {
      user {
        id
        name
      }
      message
    }
  }
`);


// gql 函数的字符串参数会被视为 Graphql 操作代码, 被识别到
const getUserInfo = gql(`
  query getUserInfo {
    userInfo {
      user {
        id
        name
      }
      message
    }
  }
`);
  • 通过注释 /* GraphQL */ 将一串字符串标记为 Graphql 操作代码
js 复制代码
// 注释 /* GraphQL */ 后面字符串, 会被视为 Graphql 操作代码, 被识别到
const gql = /* GraphQL */ `
  query getUserInfo {
    userInfo {
      user {
        id
        name
      }
      message
    }
  }
`;
  • 特定文件: 对于所有以 .gql 或 .graphql 作为后缀名的, 文件内容会被视为 Graphql 操作代码, 被识别到
gql 复制代码
query getUserInfo {
  userInfo {
    user {
      id
      name
    }
    message
  }
}

这里需要注意的是: 上面 codegen.ts 配置中 documents 并没有包含 .gql 或 .graphql 文件, 这里如果要测试, 记得补充上!!!

  1. 触发生成: 通过执行 raphql-codegen --config codegen.ts 命令, 可触发代码生成, 如下:
sh 复制代码
npx graphql-codegen --config codegen.ts

执行命令后将生成相应的代码

  • graphql/fragment-masking.ts: 使用 Graphql 片段所需要用到的 TS 以及 hooks
  • graphql/gql.ts: 代码中的所有 Graphql 操作对应 documents, 同时还导出了一个方法, 用于获取对应 Graphql document
  • graphql/graphql.ts: 根据后端 Graphql 服务生成的, 接口数据类型、参数
  • graphql/index.ts: 入口文件, 导出所有用到的方法

2.3 使用: 如何发起一个请求

下面我们就可以使用 @tanstack/react-query 和 graphql-request 来简单演示下如何使用 Graphql Codegen 生成的产物来发起一个简单的请求!

如下代码所示:

  • 直接在文件顶部编写 Graphql 操作
  • 通过 graphql-request 发送 Graphql 请求, 需要注意的是新版本的 graphql-request 不再支持相对路径, 具体可以看这篇 Issues Support passing relative path for URL #745
ts 复制代码
"use client";
import { graphql } from "@/graphql";
import request from "graphql-request";
import { useQuery } from "@tanstack/react-query";

// 1. 编写 Graphql 操作
const getUserInfoDocument = graphql(`
  query getUserInfo {
    userInfo {
      user {
        id
        name
      }
      message
    }
  }
`);

const Demo = () => {
  // 2. 请求接口
  const { data } = useQuery({
    queryKey: ["getUserInfo"],
    queryFn: async () => request("http://localhost:3000/api/graphql", getUserInfoDocument),
  });

  console.log(data);

  return <div>11</div>;
};

export default Demo;

开始前, 我们先执行 raphql-codegen --config codegen.ts 命令, 生成相关代码

sh 复制代码
npx graphql-codegen --config codegen.ts

最后启动项目, 并访问 DEMO 页面, 不出意外的话, 在控制台应该是可以看到预期的结果

2.4 简单请求函数封装

上文我们是直接调用 graphql-request 来发起请求的, 然而在实际项目中! 肯定不能这么整, 我们还是需要简单封装一个工具函数, 最些简单的封装, 目的其实就是为了处理一些个性化配置, 比如请求路径处理、请求头处理、参数处理、响应错误处理.....

如下所以, graphql-request 允许我们创建一个自己的实例, 在创建实例时我们就可以进行一些简单的配置

js 复制代码
import { GraphQLClient, ClientError } from "graphql-request";
import { createApi, BaseQueryFn } from "@reduxjs/toolkit/query/react";

// see: https://github.com/prisma-labs/graphql-request
const client = new GraphQLClient("http://localhost:3000/api/graphql", {
  mode: "cors",
  credentials: "include",
});

export default client;

调用方式也简单, 只需要调用 client.request 即可, 正如下文你所看到的, 一切都变得更加简单...

ts 复制代码
const { data } = useQuery({
  queryKey: ["getUserInfo"],
  queryFn: async () => client.request(getUserInfoDocument),
});

三、集成 VSCode

既然, 我们能够生成所有 Graphql 服务的相关 TS 配置, 那么自然要发挥其最大的作用!!! 我们希望在编写 Graphql 操作片段时, 能够提供完备的智能提示!

3.1 生成「GraphQL」服务模型

首先我们需要一份 GraphQL 后端服务的完整模型架构, 这里我们一样可以直接通过 Graphql Codegen 来帮助我们快速生成!

这里我们需要先通过 @graphql-codegen/schema-ast 插件来生成 GraphQL 后端服务的完整模型架构!! 下面我们来安装下 @graphql-codegen/schema-ast

sh 复制代码
pnpm add @graphql-codegen/schema-ast -D

接下来修改 codegen.ts 配置文件: 使用 @graphql-codegen/schema-ast 插件, 输出 GraphQL 服务模型到 schema.graphql 文件中

diff 复制代码
import type { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
  schema: "http://localhost:4000/api/graphql",
  documents: ["src/**/*.tsx"],
  ignoreNoDocuments: true,
  generates: {
    "./src/graphql/": {
      preset: "client",
    },
+   "./schema.graphql": {
+     plugins: ["schema-ast"],
+     config: {
+       includeDirectives: true,
+     },
    },
  },
};

export default config;

最后执行 npx graphql-codegen --config codegen.ts

sh 复制代码
npx graphql-codegen --config codegen.ts

最终会在项目根目录下创建预期的文件:

3.2 VSCode 配置

到目前我们只是生产了一份 GraphQL 服务模型, 但并没有将其运用起来, 下面我们需要做的就是借助 @0no-co/graphqlsp 来帮助我们更好的编写代码

  1. 安装依赖包 @0no-co/graphqlsp
sh 复制代码
pnpm add @0no-co/graphqlsp -D
  1. 修改 tsconfig.json 配置: 使用 @0no-co/graphqlsp
diff 复制代码
{
  "compilerOptions": {
    ....
    "plugins": [
+     {
+       "name": "@0no-co/graphqlsp",
+       "schema": "./schema.graphql"
+     }
    ],
  },
  ...
}
  1. 修改 .vscode/settings.json
diff 复制代码
{
  ....
+ "typescript.tsdk": "node_modules/typescript/lib",
+ "typescript.enablePromptUseWorkspaceTsdk": true
}

3.3 测试效果

到此本小节配置结束, 下面看下效果吧!

  1. 编写过程中, 会给出所有可选内容
  1. 对于不存在的字段, 会给出提示和建议
  1. ...

四、更多优化配置

到处本文的目的基本完成, 后面则是一些个人的一些配置上的优化!

4.1「Npm」脚本配置

为命令 npx graphql-codegen --config codegen.ts 配置一条 Npm 脚本, 毕竟每次手打也很麻烦!!!

所以这里我就增加有一条 Npm 脚本, 如下所示调整 package.json

diff 复制代码
{
  "name": "klx-website",
  ...
  "scripts": {
    "dev": "next dev",
    "cz": "klx-cz",
    "release": "klx-release",
    "prepare": "husky install",
+   "gql-codegen": "graphql-codegen --config codegen.ts"
  },
}

后面如需手动执行 Graphql Codegen 只需要执行:

sh 复制代码
npm run gql-codegen

4.2 开启监听模式

每次修改完 GraphQL 操作代码, 总是要手动执行 Graphql Codegen CLI 命令肯定是不靠谱的!

更好的体验肯定是只要我们修改了 GraphQL 操作代码, 在保存内容后, 能够自动执行 Graphql Codegen CLI 完成代码的生成!!

要做到这一步, 我们还需要借助 @parcel/watcher 工具! 所以我们先把该依赖包下载下来!

sh 复制代码
pnpm add @parcel/watcher -D

接下来我们就可以为 graphql-codegen 命令添加 --watch 参数, 开启监听模式, 如此只要 GraphQL 操作代码发生修改, 就会触发 graphql-codegen 命令, 生成新的代码!

最后调整下 package.json 种的 Npm 脚本: 希望在执行 dev 脚本(跑项目)的同时, 能够开启 graphql-codegen

diff 复制代码
{
  "name": "klx-website",
  ...
  "scripts": {
+   "dev": "next dev & npm run gql-codegen -- --watch",
    "cz": "klx-cz",
    "release": "klx-release",
    "prepare": "husky install",
+   "gql-codegen": "graphql-codegen --config codegen.ts"
  },
}

五、参考

相关推荐
沙漠之主7 小时前
C++编程教学设计资料:从入门到实战的完整课程方案
java·前端·c++
hasty7 小时前
不上传新包,也能改变用户拿到的版本:npm dist-tag 的 OIDC 权限治理
前端·npm·node.js
Csvn8 小时前
diff 算法(虚拟 DOM Reconciliation)
前端
前端snow9 小时前
ai agent --- 文件存储
前端
Frag0ut9 小时前
Chrome四大版本获取及共存指南:Stable/Beta/Dev/Canary
前端·chrome·浏览器·dev·beta·canary·共存版
IT_陈寒10 小时前
SpringBoot自动配置坑了我一把,原来是这样绕过去的
前端·人工智能·后端
广州华水科技10 小时前
单北斗GNSS变形监测在大坝安全监测中的应用与优势
前端
zeng不错11 小时前
B站 173 个投稿活动看到眼瞎?我写了个扩展,主打一个精准打击
前端
Latchh11 小时前
前端导出的JPEG红字发糊,质量要拉到100才清楚
前端·图像处理·人工智能·计算机视觉
默_笙11 小时前
🚦 请三个 AI 考官给 RAG 打分:量化评估实战(下)
前端·javascript