Nx 生成器生成器
为 TypeScript 项目添加一个 Nx Generator,帮助自动化重复任务,例如组件脚手架或强制特定项目结构。
使用方式
生成生成器
有两种方式可以生成生成器:
- 安装 Nx Console VSCode Plugin 如果您尚未安装
- 在VSCode中打开Nx控制台
- 点击
Generate (UI)
在"Common Nx Commands"部分 - 搜索
@aws/nx-plugin - ts#nx-generator
- 填写必需参数
- 点击
Generate
pnpm nx g @aws/nx-plugin:ts#nx-generator
yarn nx g @aws/nx-plugin:ts#nx-generator
npx nx g @aws/nx-plugin:ts#nx-generator
bunx nx g @aws/nx-plugin:ts#nx-generator
您还可以执行试运行以查看哪些文件会被更改
pnpm nx g @aws/nx-plugin:ts#nx-generator --dry-run
yarn nx g @aws/nx-plugin:ts#nx-generator --dry-run
npx nx g @aws/nx-plugin:ts#nx-generator --dry-run
bunx nx g @aws/nx-plugin:ts#nx-generator --dry-run
选项参数
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
pluginProject 必需 | string | - | TypeScript project to add the generator to. We recommend creating a ts#project in a top-level 'tools' directory. |
name 必需 | string | - | Generator name |
description | string | - | A description of your generator |
directory | string | - | The directory within the plugin project's source folder to add the generator to (default: <name>) |
生成器输出
生成器将在指定的 pluginProject
内创建以下项目文件:
文件夹src/<name>/
- schema.json 生成器的输入模式定义
- schema.d.ts 模式文件的 TypeScript 类型
- generator.ts 生成器实现桩代码
- generator.spec.ts 生成器测试用例
- generators.json 定义生成器的 Nx 配置文件
- package.json 创建或更新以添加 “generators” 入口
- tsconfig.json 更新为使用 CommonJS
本生成器会将选定的 pluginProject
更新为使用 CommonJS,因目前 Nx 生成器仅支持 CommonJS(关于 ESM 支持请参考此 GitHub issue)。
本地生成器
运行 ts#nx-generator
生成器时选择本地的 nx-plugin
项目,并指定名称及可选的目录和描述。
定义模式
schema.json
文件定义生成器接受的选项,遵循 JSON Schema 格式并包含 Nx 扩展。
基础结构
schema.json 文件基本结构如下:
{ "$schema": "https://json-schema.org/schema", "$id": "YourGeneratorName", "title": "Your Generator Title", "description": "Description of what your generator does", "type": "object", "properties": { // 生成器选项在此定义 }, "required": ["requiredOption1", "requiredOption2"]}
简单示例
基础选项的简单示例:
{ "$schema": "https://json-schema.org/schema", "$id": "ComponentGenerator", "title": "Create a Component", "description": "Creates a new React component", "type": "object", "properties": { "name": { "type": "string", "description": "Component name", "x-priority": "important" }, "directory": { "type": "string", "description": "组件生成目录", "default": "src/components" }, "withTests": { "type": "boolean", "description": "是否生成测试文件", "default": true } }, "required": ["name"]}
交互式提示 (CLI)
通过添加 x-prompt
属性自定义 CLI 运行生成器时的提示:
"name": { "type": "string", "description": "Component name", "x-prompt": "请输入组件名称?"}
布尔类型选项可使用 yes/no 提示:
"withTests": { "type": "boolean", "description": "是否生成测试文件", "x-prompt": "是否生成测试文件?"}
下拉选择
对于固定选项集合,使用 enum
创建下拉选择:
"style": { "type": "string", "description": "使用的样式方案", "enum": ["css", "scss", "styled-components", "none"], "default": "css"}
项目选择下拉
常用模式是让用户从工作区现有项目中选择:
"project": { "type": "string", "description": "目标项目", "x-prompt": "请选择要添加组件的项目:", "x-dropdown": "projects"}
x-dropdown: "projects"
属性指示 Nx 用工作区所有项目填充下拉列表。
位置参数
配置选项作为命令行位置参数:
"name": { "type": "string", "description": "组件名称", "x-priority": "important", "$default": { "$source": "argv", "index": 0 }}
用户可运行 nx g your-generator my-component
代替 nx g your-generator --name=my-component
。
设置优先级
使用 x-priority
标记重要选项:
"name": { "type": "string", "description": "组件名称", "x-priority": "important"}
优先级可为 "important"
或 "internal"
,帮助 Nx 在 VSCode 插件和 CLI 中排序属性。
默认值
为选项提供默认值:
"directory": { "type": "string", "description": "组件生成目录", "default": "src/components"}
更多信息
详细模式说明参考 Nx 生成器选项文档。
通过 schema.d.ts 生成类型
生成器会创建 schema.d.ts
文件为选项提供 TypeScript 类型:
export interface YourGeneratorSchema { name: string; directory?: string; withTests?: boolean;}
该接口用于生成器实现以提供类型安全和代码补全:
import { YourGeneratorSchema } from './schema';
export default async function (tree: Tree, options: YourGeneratorSchema) { // TypeScript 知晓所有选项类型 const { name, directory = 'src/components', withTests = true } = options; // ...}
实现生成器
创建生成器后,可在 generator.ts
中编写实现逻辑。
生成器是操作虚拟文件系统 (Tree
) 的函数,只有在生成器执行完成后才会将变更写入磁盘(“dry-run” 模式除外)。
常用操作示例:
读写文件
// 读取文件const content = tree.read('path/to/file.ts', 'utf-8');
// 写入文件tree.write('path/to/new-file.ts', 'export const hello = "world";');
// 检查文件存在性if (tree.exists('path/to/file.ts')) { // 执行操作}
模板文件生成
import { generateFiles, joinPathFragments } from '@nx/devkit';
// 从模板生成文件generateFiles( tree, joinPathFragments(__dirname, 'files'), // 模板目录 'path/to/output', // 输出目录 { // 模板变量替换 name: options.name, nameCamelCase: camelCase(options.name), nameKebabCase: kebabCase(options.name), // 添加更多变量 },);
TypeScript AST 操作
推荐安装 TSQuery 辅助 AST 操作:
import { tsquery } from '@phenomnomnominal/tsquery';import * as ts from 'typescript';
// 示例:递增文件版本号
// 将文件内容解析为 ASTconst sourceFile = tsquery.ast(tree.read('path/to/version.ts', 'utf-8'));
// 查找匹配节点const nodes = tsquery.query( sourceFile, 'VariableDeclaration:has(Identifier[name="VERSION"]) NumericLiteral',);
if (nodes.length > 0) { // 获取数值字面量节点 const numericNode = nodes[0] as ts.NumericLiteral;
// 递增版本号 const currentVersion = Number(numericNode.text); const newVersion = currentVersion + 1;
// 替换 AST 节点 const result = tsquery.replace( sourceFile, 'VariableDeclaration:has(Identifier[name="VERSION"]) NumericLiteral', () => ts.factory.createNumericLiteral(newVersion), );
// 将更新内容写回 Tree tree.write( 'path/to/version.ts', ts .createPrinter({ newLine: ts.NewLineKind.LineFeed, }) .printNode(ts.EmitHint.Unspecified, result, sourceFile), );}
添加依赖
import { addDependenciesToPackageJson } from '@nx/devkit';
// 添加 package.json 依赖addDependenciesToPackageJson( tree, { 'new-dependency': '^1.0.0', }, { 'new-dev-dependency': '^2.0.0', },);
格式化文件
import { formatFiles } from '@nx/devkit';
// 格式化所有修改过的文件await formatFiles(tree);
读写 JSON 文件
import { readJson, updateJson } from '@nx/devkit';
// 读取 JSON 文件const packageJson = readJson(tree, 'package.json');
// 更新 JSON 文件updateJson(tree, 'tsconfig.json', (json) => { json.compilerOptions = { ...json.compilerOptions, strict: true, }; return json;});
运行生成器
两种运行方式:
- 安装 Nx Console VSCode Plugin 如果您尚未安装
- 在VSCode中打开Nx控制台
- 点击
Generate (UI)
在"Common Nx Commands"部分 - 搜索
@my-project/nx-plugin - my-generator
- 填写必需参数
- 点击
Generate
pnpm nx g @my-project/nx-plugin:my-generator
yarn nx g @my-project/nx-plugin:my-generator
npx nx g @my-project/nx-plugin:my-generator
bunx nx g @my-project/nx-plugin:my-generator
您还可以执行试运行以查看哪些文件会被更改
pnpm nx g @my-project/nx-plugin:my-generator --dry-run
yarn nx g @my-project/nx-plugin:my-generator --dry-run
npx nx g @my-project/nx-plugin:my-generator --dry-run
bunx nx g @my-project/nx-plugin:my-generator --dry-run
测试生成器
生成器单元测试编写模式示例:
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';import { yourGenerator } from './generator';
describe('your generator', () => { let tree;
beforeEach(() => { // 创建空工作区树 tree = createTreeWithEmptyWorkspace();
// 添加预置文件 tree.write( 'project.json', JSON.stringify({ name: 'test-project', sourceRoot: 'src', }), );
tree.write('src/existing-file.ts', 'export const existing = true;'); });
it('应生成预期文件', async () => { // 运行生成器 await yourGenerator(tree, { name: 'test', // 其他必填参数 });
// 检查文件生成 expect(tree.exists('src/test/file.ts')).toBeTruthy();
// 检查文件内容 const content = tree.read('src/test/file.ts', 'utf-8'); expect(content).toContain('export const test');
// 可使用快照测试 expect(tree.read('src/test/file.ts', 'utf-8')).toMatchSnapshot(); });
it('应更新已有文件', async () => { await yourGenerator(tree, { name: 'test', // 其他参数 });
const content = tree.read('src/existing-file.ts', 'utf-8'); expect(content).toContain('import { test } from'); });
it('应处理错误', async () => { await expect( yourGenerator(tree, { name: 'invalid', // 触发错误的参数 }), ).rejects.toThrow('预期错误信息'); });});
测试关键点:
- 使用
createTreeWithEmptyWorkspace()
创建虚拟文件系统 - 预先设置必要文件
- 测试新文件生成和已有文件更新
- 使用快照测试复杂内容
- 测试错误处理逻辑
为 @aws/nx-plugin 贡献生成器
可使用 ts#nx-generator
在 @aws/nx-plugin
中创建生成器框架。
在仓库中运行此生成器将创建以下文件:
文件夹packages/nx-plugin/src/<name>/
- schema.json 生成器模式文件
- schema.d.ts 类型定义
- generator.ts 生成器实现
- generator.spec.ts 测试用例
文件夹docs/src/content/docs/guides/
- <name>.mdx 生成器文档页
- packages/nx-plugin/generators.json 更新包含新生成器
之后即可开始实现生成器逻辑。