Contribuisci a un Generatore
Creiamo un nuovo generatore per contribuire a @aws/nx-plugin
. Il nostro obiettivo sarà generare una nuova procedura per un’API tRPC.
Clonare il Plugin
Sezione intitolata “Clonare il Plugin”Per prima cosa, cloniamo il plugin:
git clone git@github.com:awslabs/nx-plugin-for-aws.git
Quindi installiamo e compiliamo:
cd nx-plugin-for-awspnpm ipnpm nx run-many --target build --all
Creare un Generatore Vuoto
Sezione intitolata “Creare un Generatore Vuoto”Creiamo il nuovo generatore in packages/nx-plugin/src/trpc/procedure
.
Forniamo un generatore per creare nuovi generatori, così puoi scaffoldare rapidamente il tuo nuovo generatore! Puoi eseguire questo generatore come segue:
- 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
- pluginProject: @aws/nx-plugin
- name: ts#trpc-api#procedure
- directory: trpc/procedure
- description: Adds a procedure to a tRPC API
- Clicca su
Generate
pnpm nx g @aws/nx-plugin:ts#nx-generator --pluginProject=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API
yarn nx g @aws/nx-plugin:ts#nx-generator --pluginProject=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API
npx nx g @aws/nx-plugin:ts#nx-generator --pluginProject=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API
bunx nx g @aws/nx-plugin:ts#nx-generator --pluginProject=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API
Puoi anche eseguire una prova per vedere quali file verrebbero modificati
pnpm nx g @aws/nx-plugin:ts#nx-generator --pluginProject=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API --dry-run
yarn nx g @aws/nx-plugin:ts#nx-generator --pluginProject=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API --dry-run
npx nx g @aws/nx-plugin:ts#nx-generator --pluginProject=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API --dry-run
bunx nx g @aws/nx-plugin:ts#nx-generator --pluginProject=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API --dry-run
Noterai che i seguenti file sono stati generati per te:
Directorypackages/nx-plugin/src/trpc/procedure
- schema.json Definisce gli input per il generatore
- schema.d.ts Un’interfaccia TypeScript che corrisponde allo schema
- generator.ts Funzione eseguita da Nx come generatore
- generator.spec.ts Test per il generatore
Directorydocs/src/content/docs/guides/
- trpc-procedure.mdx Documentazione per il generatore
- packages/nx-plugin/generators.json Aggiornato per includere il generatore
Aggiorniamo lo schema per aggiungere le proprietà necessarie al generatore:
{ "$schema": "https://json-schema.org/schema", "$id": "tRPCProcedure", "title": "Adds a procedure to a tRPC API", "type": "object", "properties": { "project": { "type": "string", "description": "tRPC API project", "x-prompt": "Select the tRPC API project to add the procedure to", "x-dropdown": "projects", "x-priority": "important" }, "procedure": { "description": "The name of the new procedure", "type": "string", "x-prompt": "What would you like to call your new procedure?", "x-priority": "important", }, "type": { "description": "The type of procedure to generate", "type": "string", "x-prompt": "What type of procedure would you like to generate?", "x-priority": "important", "default": "query", "enum": ["query", "mutation"] } }, "required": ["project", "procedure"]}
export interface TrpcProcedureSchema { project: string; procedure: string; type: 'query' | 'mutation';}
Noterai che il generatore è già stato collegato in packages/nx-plugin/generators.json
:
... "generators": { ... "ts#trpc-api#procedure": { "factory": "./src/trpc/procedure/generator", "schema": "./src/trpc/procedure/schema.json", "description": "Adds a procedure to a tRPC API" } },...
Implementare il Generatore
Sezione intitolata “Implementare il Generatore”Per aggiungere una procedura a un’API tRPC, dobbiamo fare due cose:
- Creare un file TypeScript per la nuova procedura
- Aggiungere la procedura al router
Creare la Nuova Procedura
Sezione intitolata “Creare la Nuova Procedura”Per creare il file TypeScript per la nuova procedura, useremo un’utility chiamata generateFiles
. Utilizzando questa, possiamo definire un template EJS che possiamo renderizzare nel nostro generatore con variabili basate sulle opzioni selezionate dall’utente.
Per prima cosa, definiamo il template in packages/nx-plugin/src/trpc/procedure/files/procedures/__procedureNameKebabCase__.ts.template
:
import { publicProcedure } from '../init.js';import { z } from 'zod/v4';
export const <%- procedureNameCamelCase %> = publicProcedure .input(z.object({ // TODO: define input })) .output(z.object({ // TODO: define output })) .<%- procedureType %>(async ({ input, ctx }) => { // TODO: implement! return {}; });
Nel template, abbiamo referenziato tre variabili:
procedureNameCamelCase
procedureNameKebabCase
procedureType
Dobbiamo quindi assicurarci di passare queste variabili a generateFiles
, insieme alla directory in cui generare i file, ovvero la posizione dei file sorgente (cioè sourceRoot
) per il progetto tRPC selezionato dall’utente come input per il generatore, che possiamo estrarre dalla configurazione del progetto.
Aggiorniamo il generatore per fare ciò:
import { generateFiles, joinPathFragments, readProjectConfiguration, Tree,} from '@nx/devkit';import { TrpcProcedureSchema } from './schema';import { formatFilesInSubtree } from '../../utils/format';import camelCase from 'lodash.camelcase';import kebabCase from 'lodash.kebabcase';
export const trpcProcedureGenerator = async ( tree: Tree, options: TrpcProcedureSchema,) => { const projectConfig = readProjectConfiguration(tree, options.project);
const procedureNameCamelCase = camelCase(options.procedure); const procedureNameKebabCase = kebabCase(options.procedure);
generateFiles( tree, joinPathFragments(__dirname, 'files'), projectConfig.sourceRoot, { procedureNameCamelCase, procedureNameKebabCase, procedureType: options.type, }, );
await formatFilesInSubtree(tree);};
export default trpcProcedureGenerator;
Aggiungere la Procedura al Router
Sezione intitolata “Aggiungere la Procedura al Router”Successivamente, vogliamo che il generatore colleghi la nuova procedura al router. Questo significa leggere e modificare il codice sorgente dell’utente!
Usiamo la manipolazione dell’AST di TypeScript per aggiornare le parti rilevanti del file sorgente TypeScript. Ci sono alcuni helper chiamati replace
e destructuredImport
per semplificare questa operazione.
import { generateFiles, joinPathFragments, readProjectConfiguration, Tree,} from '@nx/devkit';import { TrpcProcedureSchema } from './schema';import { formatFilesInSubtree } from '../../utils/format';import camelCase from 'lodash.camelcase';import kebabCase from 'lodash.kebabcase';import { destructuredImport, replace } from '../../utils/ast';import { factory, ObjectLiteralExpression } from 'typescript';
export const trpcProcedureGenerator = async ( tree: Tree, options: TrpcProcedureSchema,) => { const projectConfig = readProjectConfiguration(tree, options.project);
const procedureNameCamelCase = camelCase(options.procedure); const procedureNameKebabCase = kebabCase(options.procedure);
generateFiles( tree, joinPathFragments(__dirname, 'files'), projectConfig.sourceRoot, { procedureNameCamelCase, procedureNameKebabCase, procedureType: options.type, }, );
const routerPath = joinPathFragments(projectConfig.sourceRoot, 'router.ts');
destructuredImport( tree, routerPath, [procedureNameCamelCase], `./procedures/${procedureNameKebabCase}.js`, );
replace( tree, routerPath, 'CallExpression[expression.name="router"] > ObjectLiteralExpression', (node) => factory.createObjectLiteralExpression([ ...(node as ObjectLiteralExpression).properties, factory.createShorthandPropertyAssignment(procedureNameCamelCase), ]), );
await formatFilesInSubtree(tree);};
export default trpcProcedureGenerator;
Ora che abbiamo implementato il generatore, compiliamolo per assicurarci che sia disponibile per testarlo nel nostro progetto dungeon adventure.
pnpm nx run @aws/nx-plugin:compile
Testare il Generatore
Sezione intitolata “Testare il Generatore”Per testare il generatore, collegheremo il nostro Nx Plugin for AWS locale a una codebase esistente.
Creare un Progetto di Test con un’API tRPC
Sezione intitolata “Creare un Progetto di Test con un’API tRPC”In una directory separata, crea un nuovo workspace di test:
npx create-nx-workspace@~21.0.3 trpc-generator-test --pm=pnpm --preset=@aws/nx-plugin --ci=skip
npx create-nx-workspace@~21.0.3 trpc-generator-test --pm=yarn --preset=@aws/nx-plugin --ci=skip
npx create-nx-workspace@~21.0.3 trpc-generator-test --pm=npm --preset=@aws/nx-plugin --ci=skip
npx create-nx-workspace@~21.0.3 trpc-generator-test --pm=bun --preset=@aws/nx-plugin --ci=skip
Quindi, generiamo un’API tRPC a cui aggiungere la procedura:
- 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#trpc-api
- Compila i parametri richiesti
- apiName: test-api
- Clicca su
Generate
pnpm nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive
yarn nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive
npx nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive
bunx nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive
Puoi anche eseguire una prova per vedere quali file verrebbero modificati
pnpm nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive --dry-run
yarn nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive --dry-run
npx nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive --dry-run
bunx nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive --dry-run
Collegare il nostro Nx Plugin for AWS Locale
Sezione intitolata “Collegare il nostro Nx Plugin for AWS Locale”Nella tua codebase, colleghiamo il nostro @aws/nx-plugin
locale:
cd path/to/trpc-generator-testpnpm link path/to/nx-plugin-for-aws/dist/packages/nx-plugin
cd path/to/trpc-generator-testyarn link path/to/nx-plugin-for-aws/dist/packages/nx-plugin
cd path/to/trpc-generator-testnpm link path/to/nx-plugin-for-aws/dist/packages/nx-plugin
cd path/to/nx-plugin-for-aws/dist/packages/nx-pluginbun linkcd path/to/trpc-generator-testbun link @aws/nx-plugin
Eseguire il Nuovo Generatore
Sezione intitolata “Eseguire il Nuovo Generatore”Proviamo il nuovo generatore:
- 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#trpc-api#procedure
- Compila i parametri richiesti
- Clicca su
Generate
pnpm nx g @aws/nx-plugin:ts#trpc-api#procedure
yarn nx g @aws/nx-plugin:ts#trpc-api#procedure
npx nx g @aws/nx-plugin:ts#trpc-api#procedure
bunx nx g @aws/nx-plugin:ts#trpc-api#procedure
Puoi anche eseguire una prova per vedere quali file verrebbero modificati
pnpm nx g @aws/nx-plugin:ts#trpc-api#procedure --dry-run
yarn nx g @aws/nx-plugin:ts#trpc-api#procedure --dry-run
npx nx g @aws/nx-plugin:ts#trpc-api#procedure --dry-run
bunx nx g @aws/nx-plugin:ts#trpc-api#procedure --dry-run
Se ha successo, dovremmo aver generato una nuova procedura e aggiunto la procedura al nostro router in router.ts
.
Esercizi
Sezione intitolata “Esercizi”Se sei arrivato fin qui e hai ancora del tempo per sperimentare con i generatori Nx, ecco alcuni suggerimenti per funzionalità da aggiungere al generatore di procedure:
1. Operazioni Annidate
Sezione intitolata “1. Operazioni Annidate”Prova ad aggiornare il generatore per supportare router annidati:
- Accettando la notazione puntata per l’input
procedure
(es.games.query
) - Generando una procedura con un nome basato sulla notazione puntata inversa (es.
queryGames
) - Aggiungendo il router annidato appropriato (o aggiornandolo se esiste già!)
2. Validazione
Sezione intitolata “2. Validazione”Il nostro generatore dovrebbe prevenire potenziali problemi, come un utente che seleziona un project
che non è un’API tRPC. Dai un’occhiata al generatore api-connection
per un esempio.
3. Test Unitari
Sezione intitolata “3. Test Unitari”Scrivi alcuni test unitari per il generatore. Sono abbastanza semplici da implementare e seguono generalmente questo flusso:
- Crea un workspace tree vuoto usando
createTreeUsingTsSolutionSetup()
- Aggiungi eventuali file che dovrebbero già esistere nel tree (es.
project.json
esrc/router.ts
per un backend tRPC) - Esegui il generatore sotto test
- Verifica che le modifiche attese siano state apportate al tree
4. Test End to End
Sezione intitolata “4. Test End to End”Attualmente, abbiamo un singolo “smoke test” che esegue tutti i generatori e verifica che la build abbia successo. Questo dovrebbe essere aggiornato per includere il nuovo generatore.