Scenarios
graphql provides consistent api architecture metadata on the front and back ends, while speeding up the performance of web-backend interactions through request merging and on-demand fetching.
Use with ts
Basic idea
- scan all
gql
strings in the code
- get the
graphql
strings in the code and generate type definitions
- use these type definitions
Steps to use
Here is a demonstration using github api@v4
Get the back-end metadata
1
|
curl https://docs.github.com/public/schema.docs.graphql > schema.graphql
|
Install the base sdk
1
|
pnpm i @apollo/client graphql
|
Install code generator related dependencies
@graphql-codegen/cli
base cli
@graphql-codegen/typescript
ts plugins
@graphql-codegen/typescript-operations
ts operation generation plugin
@graphql-codegen/near-operation-file-preset
ts preset configuration
Create configuration codegen.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
overwrite: true
schema: "schema.graphql"
generates:
./src/graphql.gql.ts:
plugins:
- typescript
./:
documents:
- "src/**/*.ts"
- "!src/**/*.gql.ts"
preset: near-operation-file
presetConfig:
baseTypesPath: ./src/graphql.gql.ts
extension: .gql.ts
plugins:
- typescript-operations
|
Add some graphql variables to the code
tip: In non-react projects, please import all non-react content from @apollo/client/core
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import { gql } from "@apollo/client";
export const findRepoStar = gql`
query findRepoStar($name: String!, $owner: String!) {
repository(name: $name, owner: $owner) {
name
stargazerCount
}
}
`;
export const findRepo = gql`
query findRepo($name: String!, $owner: String!) {
repository(name: $name, owner: $owner) {
name
}
}
`;
|
Using cli to generate type definitions
1
|
pnpm graphql-codegen --config codegen.yml
|
The generated results are roughly as follows, basically the parameters and result types
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import * as Types from "../graphql.gql";
export type FindRepoStarQueryVariables = Types.Exact<{
name: Types.Scalars["String"];
owner: Types.Scalars["String"];
}>;
export type FindRepoStarQuery = {
__typename?: "Query";
repository?:
| { __typename?: "Repository"; name: string; stargazerCount: number }
| null
| undefined;
};
export type FindRepoQueryVariables = Types.Exact<{
name: Types.Scalars["String"];
owner: Types.Scalars["String"];
}>;
export type FindRepoQuery = {
__typename?: "Query";
repository?: { __typename?: "Repository"; name: string } | null | undefined;
};
|
We can use it like this
1
2
3
4
5
6
7
8
|
const res = await client.query<FindRepoStarQuery, FindRepoStarQueryVariables>({
query: findRepoStar,
variables: {
name: "liuli-tools",
owner: "rxliuli",
},
});
console.log("res: ", res);
|
Jetbrains IDE support
-
install the plugin JS GraphQL
-
create graphql base configuration file .graphqlconfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
{
"name": "github GraphQL Schema",
"schemaPath": "schema.graphql",
"extensions": {
"endpoints": {
"Default GraphQL Endpoint": {
"url": "https://api.github.com/graphql",
"headers": {
"user-agent": "JS GraphQL",
"Authorization": "bearer ${env:GITHUB_TOKEN}"
},
"introspect": false
}
}
}
}
|
-
Final effect
VSCode support
-
install the plugin Apollo GraphQL
-
add configuration apollo.config.js
1
2
3
4
5
6
7
8
|
module.exports = {
client: {
service: {
name: "github GraphQL Schema",
localSchemaFile: "./schema.graphql",
},
},
};
|
-
Final effect
Integration into vite/rollup
The reason why autogeneration should be integrated as a vite plugin was previously explained in Is it necessary to integrate the cli tool into the build tool.
vite-plugin-graphql-codegen The monitoring mode is actually buggy, so maintain a rollup plugin yourself
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import { Plugin } from "vite";
import { CodegenContext, generate, loadContext } from "@graphql-codegen/cli";
async function codegen(watch: boolean) {
const codegenContext = await loadContext();
codegenContext.updateConfig({ watch });
try {
await generate(codegenContext);
} catch (error) {
console.log("Something went wrong.");
}
}
export function graphQLCodegen(): Plugin {
let codegenContext: CodegenContext;
return {
name: "rollup-plugin-graphql-codegen",
async buildStart() {
// noinspection ES6MissingAwait
codegen(this.meta.watchMode);
},
};
}
|
Here you can actually use worker_threads
to try to accelerate multiple threads.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
import { Plugin } from "vite";
import { generate, loadContext } from "@graphql-codegen/cli";
import { isMainThread, parentPort, Worker } from "worker_threads";
import { expose, wrap } from "comlink";
import nodeEndpoint from "comlink/dist/umd/node-adapter";
async function codegen(watch: boolean) {
const codegenContext = await loadContext();
codegenContext.updateConfig({ watch });
try {
await generate(codegenContext);
} catch (error) {
console.log("Something went wrong.");
}
}
if (!isMainThread) {
expose(codegen, nodeEndpoint(parentPort!));
}
export function graphQLCodegen(): Plugin {
return {
name: "rollup-plugin-graphql-codegen",
async buildStart() {
const worker = new Worker(__filename);
try {
const codegenWorker = wrap<(watch: boolean) => void>(
nodeEndpoint(worker)
);
// noinspection ES6MissingAwait
codegenWorker(this.meta.watchMode);
} finally {
worker.unref();
}
},
};
}
|
Posted to @liuli-util/rollup-plugin-graphql-codegen
Install the chrome plugin
GraphQL Network Inspector
Reference
Other options?
- Use the rollup plugin
@rollup/plugin-graphql
to treat .graphql
files directly as importable es modules - the main issue is to deal with compatibility of related tools, mainly jest/eslint.