You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何开发可像NestJS那样生成完整文件的TypeScript CLI库?

NestJS 自定义CLI生成类库实现方案

Nest 自带的nest g xxx生成能力基于 Angular DevKit Schematics 实现,你要开发支持CLI调用、自动生成文件的自定义库,本质是开发符合Nest规范的Schematics扩展包,不需要修改Nest核心源码,按以下步骤实现即可:

1. 项目初始化与依赖安装

首先创建独立的npm包项目,安装开发依赖:

npm i -D @angular-devkit/schematics @angular-devkit/schematics-cli @nestjs/schematics typescript @types/node

项目按固定结构组织,Nest CLI会自动识别约定路径下的配置:

your-nest-generator/
├── src/
│   ├── collection.json       # 生成器集合入口配置
│   └── custom-resource/      # 单个生成器目录,可按需求新增多个
│       ├── index.ts          # 生成逻辑主代码
│       ├── schema.json       # 命令参数规则定义
│       └── files/            # 待生成的文件模板目录
│           └── __name@dasherize@if-flat__/
│               ├── __name@dasherize__.controller.ts.template
│               ├── __name@dasherize__.service.ts.template
│               └── __name@dasherize__.module.ts.template
├── package.json
└── tsconfig.json

2. 核心配置编写

首先配置collection.json,声明你提供的生成命令、别名、对应逻辑入口:

{
  "schematics": {
    "custom-resource": {
      "aliases": ["cr"],
      "factory": "./custom-resource/index#main",
      "schema": "./custom-resource/schema.json",
      "description": "生成业务自定义资源模板"
    }
  }
}

然后配置schema.json,定义命令支持的参数、默认值、交互提示:

{
  "cli": "nestjs",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "description": "生成资源的名称",
      "$default": {
        "$source": "argv",
        "index": 0
      },
      "x-prompt": "请输入资源名称"
    },
    "flat": {
      "type": "boolean",
      "default": false,
      "description": "是否跳过独立目录直接生成文件"
    }
  },
  "required": ["name"]
}

最后在package.json中添加schematics字段,让Nest CLI能识别到这是个可调用的生成包:

{
  "name": "your-nest-generator",
  "version": "1.0.0",
  "main": "dist/index.js",
  "schematics": "./dist/collection.json",
  "scripts": {
    "build": "tsc -p tsconfig.json"
  }
}

注意tsconfig编译配置要开启outDir: "dist",编译后所有配置和js文件要输出到dist目录,路径和package.json里的声明对齐。

3. 模板与生成逻辑编写

files目录下的模板文件遵循Schematics命名约定:

  • 双下划线包裹的内容是动态变量,@后面跟的是内置转换规则,比如__name@dasherize__会自动把传入的name转成短横线连接格式
  • @if-flat这类带判断的规则,会根据传入的参数决定是否生成对应目录
  • 模板内部用<%= 变量名 %>语法引用参数,内置的strings工具集提供了常用格式转换:classify转大驼峰(适合类名)、camelize转小驼峰(适合实例名)、dasherize转短横线格式(适合文件名、路由路径)

举个controller模板示例:

// __name@dasherize__.controller.ts.template
import { Controller, Get } from '@nestjs/common';
import { <%= classify(name) %>Service } from './<%= dasherize(name) %>.service';

@Controller('<%= dasherize(name) %>')
export class <%= classify(name) %>Controller {
  constructor(private readonly <%= camelize(name) %>Service: <%= classify(name) %>Service) {}

  @Get()
  list() {
    return this.<%= camelize(name) %>Service.getList();
  }
}

然后在index.ts中写生成逻辑的工厂函数,核心是读取模板、替换变量、输出到目标路径:

import { Rule, Tree, apply, url, template, mergeWith, move } from '@angular-devkit/schematics';
import { strings } from '@angular-devkit/core';
import { parseName } from '@nestjs/schematics/dist/utils/parse-name.util';

export function main(options: { name: string; flat: boolean }): Rule {
  return (tree: Tree) => {
    // 复用Nest自带的路径解析逻辑,和官方nest g命令的路径行为对齐
    const { path, name } = parseName(tree.root.path + '/src', options.name);
    
    // 加载模板、替换变量、移动到目标目录
    const generatedFiles = apply(url('./files'), [
      template({
        ...strings,
        ...options,
        name,
      }),
      move(path),
    ]);

    return mergeWith(generatedFiles);
  };
}

如果需要更复杂的逻辑,比如自动修改app.module.ts引入新生成的模块,可以直接用@nestjs/schematics导出的AST工具函数,不需要自己手写文件解析:

  • addImportToModule:自动给模块添加imports数组项
  • addDeclarationToModule:自动给模块添加declarations数组项
  • addProviderToModule:自动给模块添加providers数组项

4. 本地调试与使用

  • 执行npm run build编译TS代码到dist目录
  • 本地调试时,在生成包根目录执行npm link把包挂载到全局,然后在你的Nest业务项目里执行npm link your-nest-generator关联依赖
  • 之后就可以像调用官方生成器一样使用自定义命令:nest g your-nest-generator:custom-resource user,配置别名的话直接执行nest g your-nest-generator:cr user即可
  • 文件已存在时的覆盖提示、参数缺失时的交互输入这些能力,底层Schematics已经内置,不需要额外开发

常见踩坑点

  • 不要自己写CLI入口、命令行解析逻辑,所有命令交互、文件操作的通用逻辑Nest CLI已经封装完成,你只需要关注模板和自定义规则即可
  • 编译后要确保collection.json、模板文件都被输出到dist对应目录,否则执行命令时会报找不到模板的错误
  • 如果要给生成器传自定义参数,只需要在schema.json的properties里新增对应字段,逻辑里直接从options里取值就能用,不需要修改其他配置

内容的提问来源于stack exchange,提问作者Thanabhas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 04:27:18