引言
个人项目 《仿 Mac 个人网站开发 |项目复盘》 很早之前就用上了 Graphql, 近期对前端项目整体做了升级(转 NextJS、引入 react-query)! 在翻代码时看到之前配置的 Graphql Codegen 然后就是一脸懵逼(时间太久了, 都忘记每项配置的作用了...), 所以就重新查阅了下官网, 对这一块配置也进行了升级, 整个流程又重新走了一遍! 故而就有了本篇文章!!
一、什么是 Graphql Codegen
首先 Graphql Codegen 是一个 开发/构建 工具, 它主要的作用其实就是帮助我们自动生成 TS 类型
具体的来讲就是, 假设你的后端是 Graphql 服务, 并且在前端你是通过常规编写 Graphql 方式来调用接口的, 那么通过 Graphql Codegen 能够帮助你减少大量工作, 该工具可以监听 Graphql 操作, 并根据指定的 Graphql 服务, 生成所有必备的接口响应、请求参数等一些列 TS 类型, 甚至可以帮助你快速生成 useQuery 或 useMutation 等 hooks!!
有了它可以大大减少您必须编写的样板代码, 使得使用 GraphQL API 变得更加容易, 便捷! 并且通过简单的配置, 可以让 TS 的发挥最大化(智能提示)
二、配置讲解
其实官方已经提供了很 详细的文档, 本文只是做了些适当的简化、和说明, 所以在整个过程中, 如果遇到任何问题, 请以 官方 为准!!!!
2.1 基础配置
- 安装
@graphql-codegen/cli依赖: 提供生成代码所必要的一些CLI工具
sh
pnpm add --save-dev @graphql-codegen/cli
- 项目
根目录下创建配置文件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/graphqldocuments指定当前前端项目中可能包含Graphql操作的文件, 这个文件中如果匹配到Graphql操作代码, 则会自动生成我们预期的TS类型代码generates定义要生成的内容, 该配置是一个对象, 对象的key是生成内容文件对应的路径(可以是具体的文件、也可以是个目录), 而值则是生成的配置项(规定如果生成代码、生成怎么样的代码), 这里的配置和Babel有点像, 都是可以指定preset、plugins等内容- 更多配置内容参考: docs/config-reference/codegen-config
2.2 测试效果
是的没错, Graphql Codegen 配置很简单, 就简单的两步即可, 下面我们来看下它的效果(作用)!
- 随便找个地方, 写个页面(我这里是
NextJS项目)
ts
"use client";
const Demo = () => {
return <div>11111</div>;
};
export default Demo;
- 下面问题来了, 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文件, 这里如果要测试, 记得补充上!!!
- 触发生成: 通过执行
raphql-codegen --config codegen.ts命令, 可触发代码生成, 如下:
sh
npx graphql-codegen --config codegen.ts
执行命令后将生成相应的代码
graphql/fragment-masking.ts: 使用Graphql片段所需要用到的TS以及hooksgraphql/gql.ts: 代码中的所有Graphql操作对应documents, 同时还导出了一个方法, 用于获取对应Graphql documentgraphql/graphql.ts: 根据后端Graphql服务生成的, 接口数据类型、参数graphql/index.ts: 入口文件, 导出所有用到的方法
2.3 使用: 如何发起一个请求
下面我们就可以使用 @tanstack/react-query 和 graphql-request 来简单演示下如何使用 Graphql Codegen 生成的产物来发起一个简单的请求!
如下代码所示:
- 直接在文件顶部编写
Graphql操作- 通过
graphql-request发送Graphql请求, 需要注意的是新版本的graphql-request不再支持相对路径, 具体可以看这篇IssuesSupport 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 来帮助我们更好的编写代码
- 安装依赖包
@0no-co/graphqlsp
sh
pnpm add @0no-co/graphqlsp -D
- 修改
tsconfig.json配置: 使用@0no-co/graphqlsp
diff
{
"compilerOptions": {
....
"plugins": [
+ {
+ "name": "@0no-co/graphqlsp",
+ "schema": "./schema.graphql"
+ }
],
},
...
}
- 修改
.vscode/settings.json
diff
{
....
+ "typescript.tsdk": "node_modules/typescript/lib",
+ "typescript.enablePromptUseWorkspaceTsdk": true
}
3.3 测试效果
到此本小节配置结束, 下面看下效果吧!
- 编写过程中, 会给出所有可选内容
- 对于不存在的字段, 会给出提示和建议
- ...
四、更多优化配置
到处本文的目的基本完成, 后面则是一些个人的一些配置上的优化!
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"
},
}