Contribuer à un Générateur
Créons un nouveau générateur pour contribuer à @aws/nx-plugin
. Notre objectif sera de générer une nouvelle procédure pour une API tRPC.
Explorer le Plugin
Commencez par cloner le plugin :
git clone git@github.com:awslabs/nx-plugin-for-aws.git
Ensuite, installez et compilez :
cd nx-plugin-for-awspnpm ipnpm nx run-many --target build --all
Créer un Générateur Vide
Créons le nouveau générateur dans packages/nx-plugin/src/trpc/procedure
.
Nous fournissons un générateur pour créer de nouveaux générateurs, ce qui vous permet d’échafauder rapidement votre nouveau générateur ! Vous pouvez exécuter ce générateur comme suit :
- Installez le Nx Console VSCode Plugin si ce n'est pas déjà fait
- Ouvrez la console Nx dans VSCode
- Cliquez sur
Generate (UI)
dans la section "Common Nx Commands" - Recherchez
@aws/nx-plugin - ts#nx-generator
- Remplissez les paramètres requis
- pluginProject: @aws/nx-plugin
- name: ts#trpc-api#procedure
- directory: trpc/procedure
- description: Adds a procedure to a tRPC API
- Cliquez sur
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
Vous pouvez également effectuer une simulation pour voir quels fichiers seraient modifiés
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
Vous remarquerez que les fichiers suivants ont été générés pour vous :
Répertoirepackages/nx-plugin/src/trpc/procedure
- schema.json Définit les entrées du générateur
- schema.d.ts Une interface TypeScript correspondant au schéma
- generator.ts Fonction exécutée par Nx comme générateur
- generator.spec.ts Tests pour le générateur
Répertoiredocs/src/content/docs/guides/
- trpc-procedure.mdx Documentation du générateur
- packages/nx-plugin/generators.json Mis à jour pour inclure le générateur
Mettons à jour le schéma pour ajouter les propriétés nécessaires au générateur :
{ "$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';}
Vous remarquerez que le générateur a déjà été configuré dans 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" } },...
Implémenter le Générateur
Pour ajouter une procédure à une API tRPC, nous devons effectuer deux actions :
- Créer un fichier TypeScript pour la nouvelle procédure
- Ajouter la procédure au routeur
Créer la Nouvelle Procédure
Pour créer le fichier TypeScript de la nouvelle procédure, nous utiliserons un utilitaire appelé generateFiles
. Avec celui-ci, nous pouvons définir un template EJS que nous rendrons dans notre générateur avec des variables basées sur les options sélectionnées par l’utilisateur.
Définissons d’abord le template dans packages/nx-plugin/src/trpc/procedure/files/procedures/__procedureNameKebabCase__.ts.template
:
import { publicProcedure } from '../init.js';import { z } from 'zod';
export const <%- procedureNameCamelCase %> = publicProcedure .input(z.object({ // TODO: define input })) .output(z.object({ // TODO: define output })) .<%- procedureType %>(async ({ input, ctx }) => { // TODO: implement! return {}; });
Dans le template, nous avons référencé trois variables :
procedureNameCamelCase
procedureNameKebabCase
procedureType
Nous devons donc nous assurer de les passer à generateFiles
, ainsi que le répertoire de génération des fichiers, à savoir l’emplacement des fichiers sources (c’est-à-dire sourceRoot
) pour le projet tRPC sélectionné par l’utilisateur, que nous pouvons extraire de la configuration du projet.
Mettons à jour le générateur pour cela :
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;
Ajouter la Procédure au Routeur
Ensuite, nous voulons que le générateur connecte la nouvelle procédure au routeur. Cela implique de lire et de modifier le code source de l’utilisateur !
Nous utilisons la manipulation d’AST TypeScript pour modifier les parties pertinentes du fichier source. Des helpers comme replace
et destructuredImport
facilitent cette tâche.
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;
Maintenant que nous avons implémenté le générateur, compilons-le pour nous assurer qu’il est disponible pour le tester dans notre projet d’aventure.
pnpm nx run @aws/nx-plugin:compile
Tester le Générateur
Pour tester le générateur, nous allons lier notre Nx Plugin for AWS local à une base de code existante.
Créer un Projet de Test avec une API tRPC
Dans un répertoire séparé, créez un nouveau workspace de test :
npx create-nx-workspace@~20.6.3 trpc-generator-test --pm=pnpm --preset=ts --ci=skip --formatter=prettier
npx create-nx-workspace@~20.6.3 trpc-generator-test --pm=yarn --preset=ts --ci=skip --formatter=prettier
npx create-nx-workspace@~20.6.3 trpc-generator-test --pm=npm --preset=ts --ci=skip --formatter=prettier
npx create-nx-workspace@~20.6.3 trpc-generator-test --pm=bun --preset=ts --ci=skip --formatter=prettier
Ensuite, générons une API tRPC à laquelle ajouter la procédure :
- Installez le Nx Console VSCode Plugin si ce n'est pas déjà fait
- Ouvrez la console Nx dans VSCode
- Cliquez sur
Generate (UI)
dans la section "Common Nx Commands" - Recherchez
@aws/nx-plugin - ts#trpc-api
- Remplissez les paramètres requis
- apiName: test-api
- Cliquez sur
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
Vous pouvez également effectuer une simulation pour voir quels fichiers seraient modifiés
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
Lier notre Nx Plugin for AWS local
Dans votre base de code, lions notre @aws/nx-plugin
local :
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
Exécuter le Nouveau Générateur
Essayons le nouveau générateur :
- Installez le Nx Console VSCode Plugin si ce n'est pas déjà fait
- Ouvrez la console Nx dans VSCode
- Cliquez sur
Generate (UI)
dans la section "Common Nx Commands" - Recherchez
@aws/nx-plugin - ts#trpc-api#procedure
- Remplissez les paramètres requis
- Cliquez sur
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
Vous pouvez également effectuer une simulation pour voir quels fichiers seraient modifiés
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
En cas de succès, nous devrions avoir généré une nouvelle procédure et l’avoir ajoutée à notre routeur dans router.ts
.
Exercices
Si vous êtes arrivé jusqu’ici et avez encore du temps pour expérimenter avec les générateurs Nx, voici quelques suggestions de fonctionnalités à ajouter au générateur de procédures :
1. Opérations Imbriquées
Essayez de modifier le générateur pour supporter les routeurs imbriqués en :
- Acceptant une notation par points pour l’entrée
procedure
(ex:games.query
) - Générant une procédure avec un nom basé sur la notation inversée (ex:
queryGames
) - Ajoutant le routeur imbriqué approprié (ou le mettant à jour s’il existe déjà)
2. Validation
Notre générateur devrait se prémunir contre des problèmes potentiels, comme un utilisateur sélectionnant un project
qui n’est pas une API tRPC. Consultez le générateur api-connection
pour un exemple.
3. Tests Unitaires
Écrivez des tests unitaires pour le générateur. Ils sont relativement simples à implémenter et suivent généralement le flux suivant :
- Créer un arbre de workspace vide avec
createTreeUsingTsSolutionSetup()
- Ajouter les fichiers qui devraient déjà exister dans l’arbre (ex:
project.json
etsrc/router.ts
pour un backend tRPC) - Exécuter le générateur sous test
- Valider que les modifications attendues sont apportées à l’arbre
4. Tests End-to-End
Actuellement, nous avons un simple “smoke test” qui exécute tous les générateurs et vérifie que la compilation réussit. Celui-ci devrait être mis à jour pour inclure le nouveau générateur.