CLI 插件
警告
本章仅适用于代码优先方式。
TypeScript 的元数据反射系统有一些限制,例如无法确定一个类包含哪些属性,或者无法识别给定属性是可选的还是必需的。然而,其中一些限制可以在编译时解决。Nest 提供了一个插件,用于增强 TypeScript 编译过程,以减少所需的样板代码量。
提示
该插件是可选的。如果你愿意,可以手动声明所有装饰器,或者仅在需要的地方声明特定的装饰器。
概述
GraphQL 插件会自动:
- 使用
@Field注解所有 input object、object type 和 args 类的属性,除非使用了@HideField - 根据问号设置
nullable属性(例如,name?: string将设置nullable: true) - 根据类型设置
type属性(也支持数组) - 根据注释为属性生成描述(如果
introspectComments设置为true)
请注意,你的文件名必须具有以下后缀之一才能被插件分析:['.input.ts', '.args.ts', '.entity.ts', '.model.ts'](例如,author.entity.ts)。如果你使用不同的后缀,可以通过指定 typeFileNameSuffix 选项来调整插件的行为(见下文)。
根据我们目前学到的知识,你必须编写大量重复代码来让包知道你的类型应该如何在 GraphQL 中声明。例如,你可以定义一个简单的 Author 类如下:
// authors/models/author.model.ts
@ObjectType()
export class Author {
@Field(type => ID)
id: number;
@Field({ nullable: true })
firstName?: string;
@Field({ nullable: true })
lastName?: string;
@Field(type => [Post])
posts: Post[];
}虽然在中等规模的项目中这不是什么大问题,但一旦你有大量的类,它就会变得冗长且难以维护。
通过启用 GraphQL 插件,上面的类定义可以简单地声明为:
// authors/models/author.model.ts
@ObjectType()
export class Author {
@Field(type => ID)
id: number;
firstName?: string;
lastName?: string;
posts: Post[];
}该插件基于抽象语法树即时添加适当的装饰器。因此,你不必为散布在代码中的 @Field 装饰器而烦恼。
提示
该插件会自动生成所有缺少的 GraphQL 属性,但如果你需要覆盖它们,只需通过 @Field() 显式设置即可。
注释内省
启用注释内省功能后,CLI 插件将根据注释为字段生成描述。
例如,给定一个 roles 属性示例:
/**
* A list of user's roles
*/
@Field(() => [String], {
description: `A list of user's roles`
})
roles: string[];你必须重复描述值。启用 introspectComments 后,CLI 插件可以提取这些注释并自动为属性提供描述。现在,上面的字段可以简单地声明如下:
/**
* A list of user's roles
*/
roles: string[];使用 CLI 插件
要启用该插件,请打开 nest-cli.json(如果你使用 Nest CLI)并添加以下 plugins 配置:
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": ["@nestjs/graphql"]
}
}你可以使用 options 属性来自定义插件的行为。
{
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"plugins": [
{
"name": "@nestjs/graphql",
"options": {
"typeFileNameSuffix": [".input.ts", ".args.ts"],
"introspectComments": true
}
}
]
}
}options 属性必须满足以下接口:
export interface PluginOptions {
typeFileNameSuffix?: string[];
introspectComments?: boolean;
}| 选项 | 默认值 | 描述 |
|---|---|---|
typeFileNameSuffix | ['.input.ts', '.args.ts', '.entity.ts', '.model.ts'] | GraphQL 类型文件后缀 |
introspectComments | false | 如果设置为 true,插件将根据注释为属性生成描述 |
如果你不使用 CLI 而是有自定义的 webpack 配置,可以将此插件与 ts-loader 结合使用:
getCustomTransformers: (program: any) => ({
before: [require('@nestjs/graphql/plugin').before({}, program)]
}),SWC 构建器
对于标准设置(非 monorepo),要将 CLI 插件与 SWC 构建器一起使用,你需要启用类型检查,如此处所述。
$ nest start -b swc --type-check对于 monorepo 设置,请按照此处的说明操作。
$ npx ts-node src/generate-metadata.ts
# OR npx ts-node apps/{YOUR_APP}/src/generate-metadata.ts现在,序列化的元数据文件必须由 GraphQLModule 方法加载,如下所示:
// 由 "PluginMetadataGenerator" 自动生成的文件
import metadata from './metadata';
GraphQLModule.forRoot<...>({
..., // 其他选项
metadata,
}),与 ts-jest 集成(e2e 测试)
在启用此插件的情况下运行 e2e 测试时,你可能会遇到编译 schema 的问题。例如,最常见的错误之一是:
Object type <name> must define one or more fields.这是因为 jest 配置没有在任何地方导入 @nestjs/graphql/plugin 插件。
要修复此问题,请在你的 e2e 测试目录中创建以下文件:
const transformer = require('@nestjs/graphql/plugin');
module.exports.name = 'nestjs-graphql-transformer';
// 每次更改下面的配置时都应更改版本号 - 否则 jest 将不会检测到更改
module.exports.version = 1;
module.exports.factory = (cs) => {
return transformer.before(
{
// @nestjs/graphql/plugin 选项(可以为空)
},
cs.program, // 对于旧版本的 Jest(<= v27)使用 "cs.tsCompiler.program"
);
};完成后,在你的 jest 配置文件中导入 AST 转换器。默认情况下(在初始应用程序中),e2e 测试配置文件位于 test 文件夹下,名为 jest-e2e.json。
{
"globals": {
"ts-jest": {
"astTransformers": {
"before": ["<上面创建的文件路径>"]
}
}
}
}如果你使用 jest@^29,则使用下面的代码片段,因为之前的方法已被弃用。
{
"transform": {
"^.+\\.(t|j)s$": [
"ts-jest",
{
"astTransformers": {
"before": ["<上面创建的文件路径>"]
}
}
]
}
}