跳转到内容

Nx 生成器生成器

为 TypeScript 项目添加 Nx 生成器,帮助自动化重复任务,如组件脚手架或强制特定项目结构。

可通过两种方式生成生成器:

  1. 安装 Nx Console VSCode Plugin 如果您尚未安装
  2. 在VSCode中打开Nx控制台
  3. 点击 Generate (UI) 在"Common Nx Commands"部分
  4. 搜索 @aws/nx-plugin - ts#nx-generator
  5. 填写必需参数
    • 点击 Generate
    参数 类型 默认值 描述
    project 必需 string - TypeScript project to add the generator to. We recommend using the ts#nx-plugin generator to create this.
    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>)

    生成器将在指定 project 中创建以下项目文件:

    • 文件夹src/<name>/
      • schema.json 生成器输入模式
      • schema.d.ts 模式对应的 TypeScript 类型
      • generator.ts 生成器实现存根
      • generator.spec.ts 生成器测试
      • README.md 生成器文档
    • generators.json Nx 生成器配置
    • package.json 创建或更新以添加 “generators” 条目
    • tsconfig.json 更新为使用 CommonJS

    本生成器会将选定 project 更新为使用 CommonJS,因目前 Nx 生成器仅支持 CommonJS(ESM 支持相关 GitHub 问题)。

    运行 ts#nx-generator 时选择本地 nx-plugin 项目,并指定名称、可选目录和描述。

    schema.json 文件定义生成器接受的选项,遵循 JSON Schema 格式及 Nx 扩展

    schema.json 文件基本结构:

    {
    "$schema": "https://json-schema.org/schema",
    "$id": "YourGeneratorName",
    "title": "生成器标题",
    "description": "生成器功能描述",
    "type": "object",
    "properties": {
    // 生成器选项
    },
    "required": ["必填项1", "必填项2"]
    }

    基础选项示例:

    {
    "$schema": "https://json-schema.org/schema",
    "$id": "ComponentGenerator",
    "title": "创建组件",
    "description": "创建新 React 组件",
    "type": "object",
    "properties": {
    "name": {
    "type": "string",
    "description": "组件名称",
    "x-priority": "important"
    },
    "directory": {
    "type": "string",
    "description": "组件创建目录",
    "default": "src/components"
    },
    "withTests": {
    "type": "boolean",
    "description": "是否生成测试文件",
    "default": true
    }
    },
    "required": ["name"]
    }

    通过添加 x-prompt 属性自定义 CLI 提示:

    "name": {
    "type": "string",
    "description": "组件名称",
    "x-prompt": "请输入组件名称:"
    }

    布尔选项使用是/否提示:

    "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 定义 TypeScript 类型

    Section titled “通过 schema.d.ts 定义 TypeScript 类型”

    生成器同时创建 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” 模式除外)。空生成器示例如下:

    export const myGenerator = async (tree: Tree, options: MyGeneratorSchema) => {
    // 使用 tree 应用变更
    };
    export default myGenerator;

    常见操作示例:

    // 读取文件
    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')) {
    // 执行操作
    }

    使用 @nx/devkitgenerateFiles 工具,通过 EJS 模板生成文件:

    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),
    // 添加更多变量
    },
    );

    使用 Nx Plugin for AWS 的 tsAstReplace 方法修改 TypeScript 抽象语法树:

    import { tsAstReplace } from '@aws/nx-plugin/sdk/utils/ast';
    import * as ts from 'typescript';
    // 示例:递增版本号
    tsAstReplace(
    tree,
    'path/to/version.ts',
    'VariableDeclaration:has(Identifier[name="VERSION"]) NumericLiteral',
    (node: ts.NumericLiteral) =>
    ts.factory.createNumericLiteral(Number(node.text) + 1));
    import { addDependenciesToPackageJson } from '@nx/devkit';
    // 添加 package.json 依赖
    addDependenciesToPackageJson(
    tree,
    {
    'new-dependency': '^1.0.0',
    },
    {
    'new-dev-dependency': '^2.0.0',
    },
    );
    import { formatFilesInSubtree } from '@aws/nx-plugin/sdk/utils/format';
    // 格式化所有修改过的文件
    await formatFilesInSubtree(tree, 'optional/path/to/format');
    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;
    });

    可导入 AWS Nx 插件的生成器进行扩展,例如创建基于 TypeScript 项目的生成器:

    import { tsProjectGenerator } from '@aws/nx-plugin/sdk/ts';
    export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => {
    const callback = await tsProjectGenerator(tree, { ... });
    // 在此扩展 TypeScript 项目生成器
    // 返回回调以确保依赖安装
    // 可包装回调以执行额外操作
    return callback;
    };

    可类似方式使用和扩展 TypeScript 客户端及钩子的生成器:

    import { openApiTsClientGenerator } from '@aws/nx-plugin/sdk/open-api';
    export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => {
    await openApiTsClientGenerator(tree, { ... });
    // 在此添加额外文件
    };

    我们还提供构建 OpenAPI 规范操作迭代数据结构的方法,用于自定义代码生成:

    import { buildOpenApiCodeGenerationData } from '@aws/nx-plugin/sdk/open-api.js';
    export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => {
    const data = await buildOpenApiCodeGenerationData(tree, 'path/to/spec.json');
    generateFiles(
    tree,
    joinPathFragments(__dirname, 'files'), // 模板目录
    'path/to/output', // 输出目录
    data,
    );
    };

    模板示例:

    files/my-operations.ts.template
    export const myOperationNames = [
    <%_ allOperations.forEach((op) => { _%>
    '<%- op.name %>',
    <%_ }); _%>
    ];

    参考 GitHub 代码库获取复杂模板示例。

    两种运行方式:

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

      单元测试实现示例如下:

      import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
      import { yourGenerator } from './generator';
      describe('生成器测试', () => {
      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() 创建虚拟文件系统
      • 运行生成器前设置预置文件
      • 测试新文件创建和现有文件更新
      • 复杂内容使用快照
      • 测试错误条件确保优雅失败

      可使用 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 更新包含新生成器

      之后即可开始实现生成器。