Saltearse al contenido

Generador de Generadores de Nx

Agrega un Generador de Nx a un proyecto TypeScript para ayudarte a automatizar tareas repetitivas como la creación de componentes o la aplicación de estructuras de proyecto específicas.

Puedes generar un generador de dos formas:

  1. Instale el Nx Console VSCode Plugin si aún no lo ha hecho
  2. Abra la consola Nx en VSCode
  3. Haga clic en Generate (UI) en la sección "Common Nx Commands"
  4. Busque @aws/nx-plugin - ts#nx-generator
  5. Complete los parámetros requeridos
    • Haga clic en Generate
    Parámetro Tipo Predeterminado Descripción
    project Requerido string - TypeScript project to add the generator to. We recommend using the ts#nx-plugin generator to create this.
    name Requerido 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>)

    El generador creará los siguientes archivos en el project seleccionado:

    • Directorysrc/<nombre>/
      • schema.json Esquema para la entrada del generador
      • schema.d.ts Tipos TypeScript para tu esquema
      • generator.ts Implementación base del generador
      • generator.spec.ts Pruebas para tu generador
      • README.md Documentación del generador
    • generators.json Configuración de Nx para definir tus generadores
    • package.json Creado o actualizado para agregar entrada “generators”
    • tsconfig.json Actualizado para usar CommonJS

    Este generador actualizará el project seleccionado para usar CommonJS, ya que los generadores de Nx actualmente solo soportan CommonJS (consulta este issue de GitHub para soporte ESM).

    Selecciona tu proyecto local nx-plugin al ejecutar el generador ts#nx-generator, y especifica un nombre junto con directorio y descripción opcionales.

    El archivo schema.json define las opciones que acepta tu generador. Sigue el formato JSON Schema con extensiones específicas de Nx.

    Un archivo schema.json tiene la siguiente estructura básica:

    {
    "$schema": "https://json-schema.org/schema",
    "$id": "YourGeneratorName",
    "title": "Your Generator Title",
    "description": "Description of what your generator does",
    "type": "object",
    "properties": {
    // Tus opciones del generador van aquí
    },
    "required": ["requiredOption1", "requiredOption2"]
    }

    Aquí un ejemplo simple con algunas opciones básicas:

    {
    "$schema": "https://json-schema.org/schema",
    "$id": "ComponentGenerator",
    "title": "Create a Component",
    "description": "Crea un nuevo componente React",
    "type": "object",
    "properties": {
    "name": {
    "type": "string",
    "description": "Nombre del componente",
    "x-priority": "important"
    },
    "directory": {
    "type": "string",
    "description": "Directorio donde se creará el componente",
    "default": "src/components"
    },
    "withTests": {
    "type": "boolean",
    "description": "Generar archivos de prueba",
    "default": true
    }
    },
    "required": ["name"]
    }

    Puedes personalizar los prompts mostrados al ejecutar tu generador vía CLI agregando la propiedad x-prompt:

    "name": {
    "type": "string",
    "description": "Nombre del componente",
    "x-prompt": "¿Cuál es el nombre de tu componente?"
    }

    Para opciones booleanas, puedes usar un prompt sí/no:

    "withTests": {
    "type": "boolean",
    "description": "Generar archivos de prueba",
    "x-prompt": "¿Deseas generar archivos de prueba?"
    }

    Para opciones con un conjunto fijo de opciones, usa enum para que los usuarios puedan seleccionar:

    "style": {
    "type": "string",
    "description": "Enfoque de estilos a usar",
    "enum": ["css", "scss", "styled-components", "none"],
    "default": "css"
    }

    Un patrón común es permitir seleccionar entre proyectos existentes:

    "project": {
    "type": "string",
    "description": "Proyecto donde agregar el componente",
    "x-prompt": "¿A qué proyecto deseas agregar el componente?",
    "x-dropdown": "projects"
    }

    La propiedad x-dropdown: "projects" indica a Nx poblar el dropdown con todos los proyectos del workspace.

    Puedes configurar opciones para recibirse como argumentos posicionales:

    "name": {
    "type": "string",
    "description": "Nombre del componente",
    "x-priority": "important",
    "$default": {
    "$source": "argv",
    "index": 0
    }
    }

    Esto permite ejecutar el generador como nx g your-generator mi-componente en lugar de nx g your-generator --name=mi-componente.

    Usa la propiedad x-priority para indicar opciones importantes:

    "name": {
    "type": "string",
    "description": "Nombre del componente",
    "x-priority": "important"
    }

    Las prioridades pueden ser "important" o "internal". Esto ayuda a Nx a ordenar propiedades en la extensión VSCode y CLI.

    Puedes proveer valores por defecto:

    "directory": {
    "type": "string",
    "description": "Directorio para el componente",
    "default": "src/components"
    }

    Para más detalles sobre esquemas, consulta la documentación de Opciones de Generadores Nx.

    Junto con schema.json, el generador crea un archivo schema.d.ts con tipos TypeScript:

    export interface YourGeneratorSchema {
    name: string;
    directory?: string;
    withTests?: boolean;
    }

    Esta interfaz se usa en la implementación para seguridad de tipos:

    import { YourGeneratorSchema } from './schema';
    export default async function (tree: Tree, options: YourGeneratorSchema) {
    // TypeScript conoce los tipos de las opciones
    const { name, directory = 'src/components', withTests = true } = options;
    // ...
    }

    Tras crear el generador, puedes escribir su implementación en generator.ts.

    Un generador es una función que muta un sistema de archivos virtual (Tree). Los cambios se escriben al disco al finalizar, a menos que se ejecute en modo “dry-run”. Un generador vacío:

    export const myGenerator = async (tree: Tree, options: MyGeneratorSchema) => {
    // Usa el tree para aplicar cambios
    };
    export default myGenerator;

    Operaciones comunes en generadores:

    // Leer archivo
    const content = tree.read('ruta/al/archivo.ts', 'utf-8');
    // Escribir archivo
    tree.write('ruta/nuevo-archivo.ts', 'export const hola = "mundo";');
    // Verificar existencia
    if (tree.exists('ruta/al/archivo.ts')) {
    // Hacer algo
    }

    Usa generateFiles de @nx/devkit con plantillas EJS:

    import { generateFiles, joinPathFragments } from '@nx/devkit';
    generateFiles(
    tree,
    joinPathFragments(__dirname, 'files'), // Directorio de plantillas
    'ruta/de/salida', // Directorio de salida
    {
    name: options.name,
    nameCamelCase: camelCase(options.name),
    nameKebabCase: kebabCase(options.name),
    },
    );

    Usa tsAstReplace del Plugin Nx para AWS para modificar AST:

    import { tsAstReplace } from '@aws/nx-plugin/sdk/utils/ast';
    import * as ts from 'typescript';
    // Ejemplo: Incrementar versión
    tsAstReplace(
    tree,
    'ruta/version.ts',
    'VariableDeclaration:has(Identifier[name="VERSION"]) NumericLiteral',
    (node: ts.NumericLiteral) =>
    ts.factory.createNumericLiteral(Number(node.text) + 1));
    import { addDependenciesToPackageJson } from '@nx/devkit';
    addDependenciesToPackageJson(
    tree,
    { 'nueva-dependencia': '^1.0.0' },
    { 'nueva-dev-dependencia': '^2.0.0' },
    );
    import { formatFilesInSubtree } from '@aws/nx-plugin/sdk/utils/format';
    await formatFilesInSubtree(tree, 'ruta/opcional');
    import { readJson, updateJson } from '@nx/devkit';
    // Leer JSON
    const packageJson = readJson(tree, 'package.json');
    // Actualizar JSON
    updateJson(tree, 'tsconfig.json', (json) => {
    json.compilerOptions.strict = true;
    return json;
    });

    Importa y extiende generadores existentes:

    import { tsProjectGenerator } from '@aws/nx-plugin/sdk/ts';
    export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => {
    const callback = await tsProjectGenerator(tree, { ... });
    // Extiende aquí
    return callback;
    };

    Puedes usar generadores para clientes TypeScript:

    import { openApiTsClientGenerator } from '@aws/nx-plugin/sdk/open-api';
    export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => {
    await openApiTsClientGenerator(tree, { ... });
    // Agregar archivos
    };

    También puedes generar datos desde especificaciones OpenAPI:

    import { buildOpenApiCodeGenerationData } from '@aws/nx-plugin/sdk/open-api.js';
    export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => {
    const data = await buildOpenApiCodeGenerationData(tree, 'ruta/espec.json');
    generateFiles(tree, __dirname + '/files', 'ruta/salida', data);
    };

    Ejemplo de plantilla EJS:

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

    Consulta el repositorio en GitHub para ejemplos complejos.

    Ejecuta tu generador de dos formas:

    1. Instale el Nx Console VSCode Plugin si aún no lo ha hecho
    2. Abra la consola Nx en VSCode
    3. Haga clic en Generate (UI) en la sección "Common Nx Commands"
    4. Busque @my-project/nx-plugin - my-generator
    5. Complete los parámetros requeridos
      • Haga clic en Generate

      Pruebas unitarias típicas:

      import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
      import { yourGenerator } from './generator';
      describe('tu generador', () => {
      let tree;
      beforeEach(() => {
      tree = createTreeWithEmptyWorkspace();
      tree.write('project.json', JSON.stringify({ name: 'test-project' }));
      });
      it('debe generar archivos esperados', async () => {
      await yourGenerator(tree, { name: 'test' });
      expect(tree.exists('src/test/file.ts')).toBeTruthy();
      expect(tree.read('src/test/file.ts', 'utf-8')).toMatchSnapshot();
      });
      it('debe manejar errores', async () => {
      await expect(yourGenerator(tree, { name: 'invalido' }))
      .rejects.toThrow('Mensaje de error esperado');
      });
      });

      Puntos clave:

      • Usa createTreeWithEmptyWorkspace()
      • Prueba creación y actualización de archivos
      • Usa snapshots para contenido complejo
      • Prueba condiciones de error

      Usa ts#nx-generator para crear generadores dentro de @aws/nx-plugin.

      Al ejecutarlo en nuestro repositorio, genera:

      • Directorypackages/nx-plugin/src/<nombre>/
        • schema.json
        • schema.d.ts
        • generator.ts
        • generator.spec.ts
      • Directorydocs/src/content/docs/guides/
        • <nombre>.mdx
      • packages/nx-plugin/generators.json Actualizado