跳转到内容

贡献生成器

让我们为@aws/nx-plugin创建一个新的生成器来贡献代码。我们的目标是为tRPC API生成新的procedure。

首先克隆插件仓库:

Terminal window
git clone git@github.com:awslabs/nx-plugin-for-aws.git

安装依赖并构建:

Terminal window
cd nx-plugin-for-aws
pnpm i
pnpm nx run-many --target build --all

packages/nx-plugin/src/trpc/procedure目录下创建新生成器。

我们提供了创建生成器的生成器,可以快速搭建新生成器!运行以下命令:

  1. 安装 Nx Console VSCode Plugin 如果您尚未安装
  2. 在VSCode中打开Nx控制台
  3. 点击 Generate (UI) 在"Common Nx Commands"部分
  4. 搜索 @aws/nx-plugin - ts#nx-generator
  5. 填写必需参数
    • pluginProject: @aws/nx-plugin
    • name: ts#trpc-api#procedure
    • directory: trpc/procedure
    • description: Adds a procedure to a tRPC API
  6. 点击 Generate

以下文件已自动生成:

  • 文件夹packages/nx-plugin/src/trpc/procedure
    • schema.json 定义生成器输入
    • schema.d.ts 与schema匹配的TypeScript接口
    • generator.ts Nx运行的生成器函数
    • generator.spec.ts 生成器测试
  • 文件夹docs/src/content/docs/guides/
    • trpc-procedure.mdx 生成器文档
  • packages/nx-plugin/generators.json 更新包含生成器

更新schema添加生成器所需属性:

{
"$schema": "https://json-schema.org/schema",
"$id": "tRPCProcedure",
"title": "Adds a procedure to a tRPC API",
"type": "object",
"properties": {
"project": {
"type": "string",
"description": "tRPC API project",
"x-prompt": "Select the tRPC API project to add the procedure to",
"x-dropdown": "projects",
"x-priority": "important"
},
"procedure": {
"description": "The name of the new procedure",
"type": "string",
"x-prompt": "What would you like to call your new procedure?",
"x-priority": "important",
},
"type": {
"description": "The type of procedure to generate",
"type": "string",
"x-prompt": "What type of procedure would you like to generate?",
"x-priority": "important",
"default": "query",
"enum": ["query", "mutation"]
}
},
"required": ["project", "procedure"]
}

生成器已自动注册到packages/nx-plugin/generators.json

...
"generators": {
...
"ts#trpc-api#procedure": {
"factory": "./src/trpc/procedure/generator",
"schema": "./src/trpc/procedure/schema.json",
"description": "Adds a procedure to a tRPC API"
}
},
...

为tRPC API添加procedure需要完成两个步骤:

  1. 创建新procedure的TypeScript文件
  2. 将procedure添加到router

使用generateFiles工具创建TypeScript文件。通过EJS模板根据用户选项生成内容。

packages/nx-plugin/src/trpc/procedure/files/procedures/__procedureNameKebabCase__.ts.template定义模板:

files/procedures/__procedureNameKebabCase__.ts.template
import { publicProcedure } from '../init.js';
import { z } from 'zod';
export const <%- procedureNameCamelCase %> = publicProcedure
.input(z.object({
// TODO: define input
}))
.output(z.object({
// TODO: define output
}))
.<%- procedureType %>(async ({ input, ctx }) => {
// TODO: implement!
return {};
});

模板中引用了三个变量:

  • procedureNameCamelCase
  • procedureNameKebabCase
  • procedureType

需要将这些变量传递给generateFiles,并确定生成文件的目标目录(即用户选择的tRPC项目的源码目录)。

更新生成器代码:

procedure/generator.ts
import {
generateFiles,
joinPathFragments,
readProjectConfiguration,
Tree,
} from '@nx/devkit';
import { TrpcProcedureSchema } from './schema';
import { formatFilesInSubtree } from '../../utils/format';
import camelCase from 'lodash.camelcase';
import kebabCase from 'lodash.kebabcase';
export const trpcProcedureGenerator = async (
tree: Tree,
options: TrpcProcedureSchema,
) => {
const projectConfig = readProjectConfiguration(tree, options.project);
const procedureNameCamelCase = camelCase(options.procedure);
const procedureNameKebabCase = kebabCase(options.procedure);
generateFiles(
tree,
joinPathFragments(__dirname, 'files'),
projectConfig.sourceRoot,
{
procedureNameCamelCase,
procedureNameKebabCase,
procedureType: options.type,
},
);
await formatFilesInSubtree(tree);
};
export default trpcProcedureGenerator;

需要读取并修改用户源码中的router文件。使用TypeScript AST操作工具来更新代码。

procedure/generator.ts
import {
generateFiles,
joinPathFragments,
readProjectConfiguration,
Tree,
} from '@nx/devkit';
import { TrpcProcedureSchema } from './schema';
import { formatFilesInSubtree } from '../../utils/format';
import camelCase from 'lodash.camelcase';
import kebabCase from 'lodash.kebabcase';
import { destructuredImport, replace } from '../../utils/ast';
import { factory, ObjectLiteralExpression } from 'typescript';
export const trpcProcedureGenerator = async (
tree: Tree,
options: TrpcProcedureSchema,
) => {
const projectConfig = readProjectConfiguration(tree, options.project);
const procedureNameCamelCase = camelCase(options.procedure);
const procedureNameKebabCase = kebabCase(options.procedure);
generateFiles(
tree,
joinPathFragments(__dirname, 'files'),
projectConfig.sourceRoot,
{
procedureNameCamelCase,
procedureNameKebabCase,
procedureType: options.type,
},
);
const routerPath = joinPathFragments(projectConfig.sourceRoot, 'router.ts');
destructuredImport(
tree,
routerPath,
[procedureNameCamelCase],
`./procedures/${procedureNameKebabCase}.js`,
);
replace(
tree,
routerPath,
'CallExpression[expression.name="router"] > ObjectLiteralExpression',
(node) =>
factory.createObjectLiteralExpression([
...(node as ObjectLiteralExpression).properties,
factory.createShorthandPropertyAssignment(procedureNameCamelCase),
]),
);
await formatFilesInSubtree(tree);
};
export default trpcProcedureGenerator;

编译生成器使其可用:

Terminal window
pnpm nx run @aws/nx-plugin:compile

将本地Nx Plugin for AWS链接到现有代码库进行测试。

在新目录创建测试工作区:

Terminal window
npx create-nx-workspace@~21.0.3 trpc-generator-test --pm=pnpm --preset=@aws/nx-plugin --ci=skip

生成tRPC API:

  1. 安装 Nx Console VSCode Plugin 如果您尚未安装
  2. 在VSCode中打开Nx控制台
  3. 点击 Generate (UI) 在"Common Nx Commands"部分
  4. 搜索 @aws/nx-plugin - ts#trpc-api
  5. 填写必需参数
    • apiName: test-api
  6. 点击 Generate

链接本地@aws/nx-plugin

Terminal window
cd path/to/trpc-generator-test
pnpm link path/to/nx-plugin-for-aws/dist/packages/nx-plugin

执行新生成器:

  1. 安装 Nx Console VSCode Plugin 如果您尚未安装
  2. 在VSCode中打开Nx控制台
  3. 点击 Generate (UI) 在"Common Nx Commands"部分
  4. 搜索 @aws/nx-plugin - ts#trpc-api#procedure
  5. 填写必需参数
    • 点击 Generate

    成功运行后,将生成新procedure并添加到router.ts中。

    如需进一步探索Nx生成器,可尝试以下功能增强:

    支持嵌套router:

    • 允许procedure输入使用点符号(如games.query
    • 根据反转点符号生成procedure名称(如queryGames
    • 添加或更新嵌套router

    防止用户选择非tRPC项目,可参考api-connection生成器的实现。

    编写生成器单元测试:

    1. 使用createTreeUsingTsSolutionSetup()创建空工作区树
    2. 添加预存文件(如project.jsonsrc/router.ts
    3. 运行生成器
    4. 验证树结构变更

    当前”smoke test”仅验证构建成功,需更新测试包含新生成器。