Generatore di Generatori Nx
Aggiunge un Generatore Nx a un progetto TypeScript, per aiutarti ad automatizzare attività ripetitive come lo scaffolding di componenti o l’imposizione di strutture di progetto specifiche.
Utilizzo
Generare un Generatore
Puoi generare un generatore in due modi:
- Installa il Nx Console VSCode Plugin se non l'hai già fatto
- Apri la console Nx in VSCode
- Clicca su
Generate (UI)
nella sezione "Common Nx Commands" - Cerca
@aws/nx-plugin - ts#nx-generator
- Compila i parametri richiesti
- Clicca su
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
Puoi anche eseguire una prova per vedere quali file verrebbero modificati
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
Opzioni
Parametro | Tipo | Predefinito | Descrizione |
---|---|---|---|
pluginProject Obbligatorio | string | - | TypeScript project to add the generator to. We recommend creating a ts#project in a top-level 'tools' directory. |
name Obbligatorio | 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>) |
Output del Generatore
Il generatore creerà i seguenti file all’interno del pluginProject
specificato:
Directorysrc/<name>/
- schema.json Schema per l’input del generatore
- schema.d.ts Tipi TypeScript per lo schema
- generator.ts Implementazione stub del generatore
- generator.spec.ts Test per il generatore
- generators.json Configurazione Nx per definire i generatori
- package.json Creato o aggiornato con una voce “generators”
- tsconfig.json Aggiornato per usare CommonJS
Questo generatore aggiornerà il pluginProject
selezionato per utilizzare CommonJS, poiché i generatori Nx supportano attualmente solo CommonJS (fai riferimento a questa issue GitHub per il supporto ESM).
Generator Locali
Consigliamo di generare prima un progetto TypeScript dedicato per tutti i tuoi generatori utilizzando il generatore ts#project
. Ad esempio:
- Installa il Nx Console VSCode Plugin se non l'hai già fatto
- Apri la console Nx in VSCode
- Clicca su
Generate (UI)
nella sezione "Common Nx Commands" - Cerca
@aws/nx-plugin - ts#project
- Compila i parametri richiesti
- name: nx-plugin
- directory: tools
- Clicca su
Generate
pnpm nx g @aws/nx-plugin:ts#project --name=nx-plugin --directory=tools
yarn nx g @aws/nx-plugin:ts#project --name=nx-plugin --directory=tools
npx nx g @aws/nx-plugin:ts#project --name=nx-plugin --directory=tools
bunx nx g @aws/nx-plugin:ts#project --name=nx-plugin --directory=tools
Puoi anche eseguire una prova per vedere quali file verrebbero modificati
pnpm nx g @aws/nx-plugin:ts#project --name=nx-plugin --directory=tools --dry-run
yarn nx g @aws/nx-plugin:ts#project --name=nx-plugin --directory=tools --dry-run
npx nx g @aws/nx-plugin:ts#project --name=nx-plugin --directory=tools --dry-run
bunx nx g @aws/nx-plugin:ts#project --name=nx-plugin --directory=tools --dry-run
Seleziona il tuo progetto locale nx-plugin
quando esegui il generatore ts#nx-generator
, e specifica un nome con directory e descrizione opzionali.
Definizione dello Schema
Il file schema.json
definisce le opzioni accettate dal generatore. Segue il formato JSON Schema con estensioni specifiche di Nx.
Struttura Base
Un file schema.json ha la seguente struttura base:
{ "$schema": "https://json-schema.org/schema", "$id": "YourGeneratorName", "title": "Your Generator Title", "description": "Description of what your generator does", "type": "object", "properties": { // Le opzioni del generatore vanno qui }, "required": ["requiredOption1", "requiredOption2"]}
Esempio Semplice
Ecco un esempio semplice con alcune opzioni di base:
{ "$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": "Directory where the component will be created", "default": "src/components" }, "withTests": { "type": "boolean", "description": "Whether to generate test files", "default": true } }, "required": ["name"]}
Prompt Interattivi (CLI)
Puoi personalizzare i prompt visualizzati durante l’esecuzione del generatore via CLI aggiungendo la proprietà x-prompt
:
"name": { "type": "string", "description": "Component name", "x-prompt": "What is the name of your component?"}
Per opzioni booleane, puoi usare un prompt sì/no:
"withTests": { "type": "boolean", "description": "Whether to generate test files", "x-prompt": "Would you like to generate test files?"}
Selezione a Tendina
Per opzioni con un set fisso di scelte, usa enum
per permettere agli utenti di selezionare un’opzione.
"style": { "type": "string", "description": "The styling approach to use", "enum": ["css", "scss", "styled-components", "none"], "default": "css"}
Selezione Progetto a Tendina
Un pattern comune è permettere agli utenti di selezionare da progetti esistenti nel workspace:
"project": { "type": "string", "description": "The project to add the component to", "x-prompt": "Which project would you like to add the component to?", "x-dropdown": "projects"}
La proprietà x-dropdown: "projects"
indica a Nx di popolare la tendina con tutti i progetti nel workspace.
Argomenti Posizionali
Puoi configurare opzioni da passare come argomenti posizionali quando si esegue il generatore da riga di comando:
"name": { "type": "string", "description": "Component name", "x-priority": "important", "$default": { "$source": "argv", "index": 0 }}
Questo permette agli utenti di eseguire il generatore come nx g your-generator my-component
invece di nx g your-generator --name=my-component
.
Impostazione Priorità
Usa la proprietà x-priority
per indicare le opzioni più importanti:
"name": { "type": "string", "description": "Component name", "x-priority": "important"}
Le opzioni possono avere priorità "important"
o "internal"
. Questo aiuta Nx a ordinare le proprietà nell’estensione VSCode di Nx e nella CLI Nx.
Valori Predefiniti
Puoi fornire valori predefiniti per le opzioni:
"directory": { "type": "string", "description": "Directory where the component will be created", "default": "src/components"}
Ulteriori Informazioni
Per maggiori dettagli sugli schemi, consulta la documentazione Nx Generator Options.
Tipi TypeScript con schema.d.ts
Insieme a schema.json
, il generatore crea un file schema.d.ts
che fornisce tipi TypeScript per le opzioni del generatore:
export interface YourGeneratorSchema { name: string; directory?: string; withTests?: boolean;}
Questa interfaccia è usata nell’implementazione del generatore per garantire type safety e completamento del codice:
import { YourGeneratorSchema } from './schema';
export default async function (tree: Tree, options: YourGeneratorSchema) { // TypeScript conosce i tipi di tutte le opzioni const { name, directory = 'src/components', withTests = true } = options; // ...}
Ogni volta che modifichi schema.json
, devi aggiornare schema.d.ts
per corrispondere. Questo include:
- Aggiungere o rimuovere proprietà
- Cambiare i tipi delle proprietà
- Rendere proprietà obbligatorie o opzionali (usa il suffisso
?
per proprietà opzionali)
L’interfaccia TypeScript deve riflettere accuratamente la struttura definita nel tuo JSON schema.
Implementazione di un Generatore
Dopo aver creato il nuovo generatore come sopra, puoi scrivere la tua implementazione in generator.ts
.
Un generatore è una funzione che modifica un filesystem virtuale (Tree
), leggendo e scrivendo file per apportare le modifiche desiderate. Le modifiche dal Tree
vengono scritte su disco solo al termine dell’esecuzione del generatore, a meno che non sia eseguito in modalità “dry-run”.
Ecco alcune operazioni comuni che potresti voler eseguire nel generatore:
Lettura e Scrittura di File
// Leggi un fileconst content = tree.read('path/to/file.ts', 'utf-8');
// Scrivi un filetree.write('path/to/new-file.ts', 'export const hello = "world";');
// Verifica se un file esisteif (tree.exists('path/to/file.ts')) { // Fai qualcosa}
Generazione File da Template
Puoi generare file con l’utility generateFiles
da @nx/devkit
. Questo permette di definire template in sintassi EJS e sostituire variabili.
import { generateFiles, joinPathFragments } from '@nx/devkit';
// Genera file da templategenerateFiles( tree, joinPathFragments(__dirname, 'files'), // Directory template 'path/to/output', // Directory di output { // Variabili da sostituire nei template name: options.name, nameCamelCase: camelCase(options.name), nameKebabCase: kebabCase(options.name), // Aggiungi altre variabili se necessario },);
Manipolazione AST (Abstract Syntax Tree) TypeScript
Puoi usare il metodo tsAstReplace
esposto dal Nx Plugin for AWS per sostituire parti di un abstract syntax tree TypeScript.
import { tsAstReplace } from '@aws/nx-plugin/sdk/utils/ast';import * as ts from 'typescript';
// Esempio: Incrementa numero di versione in un filetsAstReplace( tree, 'path/to/version.ts', 'VariableDeclaration:has(Identifier[name="VERSION"]) NumericLiteral', (node: ts.NumericLiteral) => ts.factory.createNumericLiteral(Number(node.text) + 1));
Puoi testare i selettori online nel TSQuery Playground.
Aggiunta Dipendenze
import { addDependenciesToPackageJson } from '@nx/devkit';
// Aggiungi dipendenze a package.jsonaddDependenciesToPackageJson( tree, { 'new-dependency': '^1.0.0', }, { 'new-dev-dependency': '^2.0.0', },);
Se aggiungi dipendenze a un package.json, puoi installarle per l’utente come parte del callback del generatore:
import { installPackagesTask } from '@nx/devkit';
// I generatori restituiscono un callback che può eseguire task post-generazione, come installare dipendenzereturn () => { installPackagesTask(tree);};
Formattazione File Generati
import { formatFilesInSubtree } from '@aws/nx-plugin/sdk/utils/format';
// Formatta tutti i file modificatiawait formatFilesInSubtree(tree, 'optional/path/to/format');
Lettura e Aggiornamento File JSON
import { readJson, updateJson } from '@nx/devkit';
// Leggi un file JSONconst packageJson = readJson(tree, 'package.json');
// Aggiorna un file JSONupdateJson(tree, 'tsconfig.json', (json) => { json.compilerOptions = { ...json.compilerOptions, strict: true, }; return json;});
Estensione di un Generatore dal Nx Plugin for AWS
Puoi importare generatori dal Nx Plugin for AWS ed estenderli o combinarli come desideri. Ad esempio, potresti creare un generatore che si basa su un progetto TypeScript:
import { tsProjectGenerator } from '@aws/nx-plugin/sdk/ts';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { const callback = await tsProjectGenerator(tree, { ... });
// Estendi qui il generatore di progetto TypeScript
// Restituisci il callback per assicurare l'installazione delle dipendenze. // Puoi wrappare il callback se desideri eseguire operazioni aggiuntive nel callback del generatore. return callback;};
Generator OpenAPI
Puoi usare ed estendere i generatori che utilizziamo per client e hook TypeScript in modo simile a quanto sopra:
import { openApiTsClientGenerator } from '@aws/nx-plugin/sdk/open-api';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { await openApiTsClientGenerator(tree, { ... });
// Aggiungi file aggiuntivi qui};
Esponiamo anche un metodo che ti permette di costruire una struttura dati utilizzabile per iterare sulle operazioni in una specifica OpenAPI e quindi strumentare la tua generazione di codice, ad esempio:
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'), // Directory template 'path/to/output', // Directory di output data, );};
Il che ti permette di scrivere template come:
export const myOperationNames = [<%_ allOperations.forEach((op) => { _%> '<%- op.name %>',<%_ }); _%>];
Fai riferimento al codice sorgente su GitHub per esempi di template più complessi.
Esecuzione del Generatore
Puoi eseguire il generatore in due modi:
- Installa il Nx Console VSCode Plugin se non l'hai già fatto
- Apri la console Nx in VSCode
- Clicca su
Generate (UI)
nella sezione "Common Nx Commands" - Cerca
@my-project/nx-plugin - my-generator
- Compila i parametri richiesti
- Clicca su
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
Puoi anche eseguire una prova per vedere quali file verrebbero modificati
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
Se non vedi il tuo generatore nell’interfaccia UI del plugin VSCode, puoi aggiornare il tuo Nx Workspace con:
pnpm nx reset
yarn nx reset
npx nx reset
bunx nx reset
Test del Generatore
I test unitari per i generatori sono semplici da implementare. Ecco un pattern tipico:
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';import { yourGenerator } from './generator';
describe('your generator', () => { let tree;
beforeEach(() => { // Crea un workspace tree vuoto tree = createTreeWithEmptyWorkspace();
// Aggiungi file che devono esistere nel tree tree.write( 'project.json', JSON.stringify({ name: 'test-project', sourceRoot: 'src', }), );
tree.write('src/existing-file.ts', 'export const existing = true;'); });
it('dovrebbe generare i file attesi', async () => { // Esegui il generatore await yourGenerator(tree, { name: 'test', // Aggiungi altre opzioni richieste });
// Verifica che i file siano stati creati expect(tree.exists('src/test/file.ts')).toBeTruthy();
// Controlla il contenuto del file const content = tree.read('src/test/file.ts', 'utf-8'); expect(content).toContain('export const test');
// Puoi usare anche gli snapshot expect(tree.read('src/test/file.ts', 'utf-8')).toMatchSnapshot(); });
it('dovrebbe aggiornare file esistenti', async () => { // Esegui il generatore await yourGenerator(tree, { name: 'test', // Aggiungi altre opzioni richieste });
// Verifica che i file esistenti siano stati aggiornati const content = tree.read('src/existing-file.ts', 'utf-8'); expect(content).toContain('import { test } from'); });
it('dovrebbe gestire gli errori', async () => { // Aspettati che il generatore sollevi un errore in certe condizioni await expect( yourGenerator(tree, { name: 'invalid', // Aggiungi opzioni che dovrebbero causare un errore }), ).rejects.toThrow('Messaggio di errore atteso'); });});
Punti chiave per testare i generatori:
- Usa
createTreeWithEmptyWorkspace()
per creare un filesystem virtuale - Imposta file prerequisiti prima di eseguire il generatore
- Testa sia la creazione di nuovi file che l’aggiornamento di file esistenti
- Usa snapshot per contenuti di file complessi
- Testa condizioni di errore per assicurarti che il generatore fallisca correttamente
Contribuire ai Generatori per @aws/nx-plugin
Puoi usare ts#nx-generator
anche per scaffoldare un generatore all’interno di @aws/nx-plugin
.
Quando questo generatore viene eseguito nel nostro repository, genererà i seguenti file:
Directorypackages/nx-plugin/src/<name>/
- schema.json Schema per l’input del generatore
- schema.d.ts Tipi TypeScript per lo schema
- generator.ts Implementazione del generatore
- generator.spec.ts Test per il generatore
Directorydocs/src/content/docs/guides/
- <name>.mdx Pagina di documentazione per il generatore
- packages/nx-plugin/generators.json Aggiornato per includere il generatore
Potrai quindi iniziare a implementare il tuo generatore.
Per una guida più approfondita su come contribuire al Nx Plugin for AWS, consulta il tutorial qui.