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.
Récupérer le plugin
Section intitulée « Récupérer le plugin »Tout d’abord, clonons le plugin :
git clone git@github.com:awslabs/nx-plugin-for-aws.gitEnsuite, installons et construisons :
cd nx-plugin-for-awspnpm ipnpm nx run-many --target build --allCréer un générateur vide
Section intitulée « 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 afin que vous puissiez rapidement échafauder votre nouveau générateur ! Vous pouvez exécuter ce générateur comme suit :
pnpm nx g @aws/nx-plugin:ts#nx-generator --project=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC APIyarn nx g @aws/nx-plugin:ts#nx-generator --project=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC APInpx nx g @aws/nx-plugin:ts#nx-generator --project=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC APIbunx nx g @aws/nx-plugin:ts#nx-generator --project=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC APIVous pouvez également effectuer une simulation pour voir quels fichiers seraient modifiés
pnpm nx g @aws/nx-plugin:ts#nx-generator --project=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API --dry-runyarn nx g @aws/nx-plugin:ts#nx-generator --project=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API --dry-runnpx nx g @aws/nx-plugin:ts#nx-generator --project=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API --dry-runbunx nx g @aws/nx-plugin:ts#nx-generator --project=@aws/nx-plugin --name=ts#trpc-api#procedure --directory=trpc/procedure --description=Adds a procedure to a tRPC API --dry-run- 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
- project: @aws/nx-plugin
- name: ts#trpc-api#procedure
- directory: trpc/procedure
- description: Adds a procedure to a tRPC API
- Cliquez sur
Generate
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 l’entrée pour le générateur
- schema.d.ts Une interface TypeScript qui correspond au schéma
- generator.ts Fonction que Nx exécute en tant que générateur
- generator.spec.ts Tests pour le générateur
Répertoiredocs/src/content/docs/guides/
- trpc-procedure.mdx Documentation pour le 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 dont nous aurons besoin pour le 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é connecté 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
Section intitulée « Implémenter le générateur »Pour ajouter une procédure à une API tRPC, nous devons faire deux choses :
- Créer un fichier TypeScript pour la nouvelle procédure
- Ajouter la procédure au routeur
Créer la nouvelle procédure
Section intitulée « Créer la nouvelle procédure »Pour créer le fichier TypeScript pour la nouvelle procédure, nous utiliserons un utilitaire appelé generateFiles. En l’utilisant, nous pouvons définir un modèle EJS que nous pouvons rendre dans notre générateur avec des variables basées sur les options sélectionnées par l’utilisateur.
Tout d’abord, nous définirons le modèle 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 modèle, nous avons référencé trois variables :
procedureNameCamelCaseprocedureNameKebabCaseprocedureType
Nous devrons donc nous assurer de les transmettre à generateFiles, ainsi que le répertoire dans lequel générer les fichiers, à savoir l’emplacement des fichiers sources (c’est-à-dire sourceRoot) pour le projet tRPC que l’utilisateur a sélectionné comme entrée pour le générateur, que nous pouvons extraire de la configuration du projet.
Mettons à jour le générateur pour faire cela :
import { generateFiles, joinPathFragments, readProjectConfiguration, type Tree,} from '@nx/devkit';import type { TrpcProcedureSchema } from './schema.js';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(import.meta.dirname, 'files'), projectConfig.sourceRoot, { procedureNameCamelCase, procedureNameKebabCase, procedureType: options.type, }, );
await formatFilesInSubtree(tree);};
export default trpcProcedureGenerator;Ajouter la procédure au routeur
Section intitulée « Ajouter la procédure au routeur »Ensuite, nous voulons que le générateur connecte la nouvelle procédure au routeur. Cela signifie lire et mettre à jour le code source de l’utilisateur !
Nous utilisons GritQL pour rechercher et transformer de manière déclarative le code source. L’assistant addDestructuredImport ajoute des imports nommés, et applyGritQL applique un motif GritQL pour ajouter la procédure au littéral d’objet du routeur.
import { generateFiles, joinPathFragments, readProjectConfiguration, type Tree,} from '@nx/devkit';import type { TrpcProcedureSchema } from './schema.js';import { formatFilesInSubtree } from '../../utils/format';import camelCase from 'lodash.camelcase';import kebabCase from 'lodash.kebabcase';import { addDestructuredImport, applyGritQL } from '../../utils/ast';
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(import.meta.dirname, 'files'), projectConfig.sourceRoot, { procedureNameCamelCase, procedureNameKebabCase, procedureType: options.type, }, );
const routerPath = joinPathFragments(projectConfig.sourceRoot, 'router.ts');
await addDestructuredImport( tree, routerPath, [procedureNameCamelCase], `./procedures/${procedureNameKebabCase}.js`, );
await applyGritQL( tree, routerPath, `\`router({ $props })\` => \`router({ $props, ${procedureNameCamelCase} })\` where { $props <: not contains \`${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 que nous puissions le tester dans notre projet d’aventure de donjon.
pnpm nx compile @aws/nx-pluginTester le générateur
Section intitulée « 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
Section intitulée « Créer un projet de test avec une API tRPC »Dans un répertoire séparé, créez un nouvel espace de travail de test :
pnpm create @aws/nx-workspace trpc-generator-testyarn create @aws/nx-workspace trpc-generator-testnpm create @aws/nx-workspace -- trpc-generator-testbun create @aws/nx-workspace trpc-generator-testEnsuite, générons une API tRPC à laquelle ajouter la procédure :
pnpm nx g @aws/nx-plugin:ts#api --name=test-api --framework=trpc --no-interactiveyarn nx g @aws/nx-plugin:ts#api --name=test-api --framework=trpc --no-interactivenpx nx g @aws/nx-plugin:ts#api --name=test-api --framework=trpc --no-interactivebunx nx g @aws/nx-plugin:ts#api --name=test-api --framework=trpc --no-interactiveVous pouvez également effectuer une simulation pour voir quels fichiers seraient modifiés
pnpm nx g @aws/nx-plugin:ts#api --name=test-api --framework=trpc --no-interactive --dry-runyarn nx g @aws/nx-plugin:ts#api --name=test-api --framework=trpc --no-interactive --dry-runnpx nx g @aws/nx-plugin:ts#api --name=test-api --framework=trpc --no-interactive --dry-runbunx nx g @aws/nx-plugin:ts#api --name=test-api --framework=trpc --no-interactive --dry-run- 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#api - Remplissez les paramètres requis
- name: test-api
- framework: trpc
- Cliquez sur
Generate
Lier notre Nx Plugin for AWS local
Section intitulée « 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-plugincd path/to/trpc-generator-testyarn link path/to/nx-plugin-for-aws/dist/packages/nx-plugincd path/to/trpc-generator-testnpm link path/to/nx-plugin-for-aws/dist/packages/nx-plugincd path/to/nx-plugin-for-aws/dist/packages/nx-pluginbun linkcd path/to/trpc-generator-testbun link @aws/nx-pluginExécuter le nouveau générateur
Section intitulée « Exécuter le nouveau générateur »Essayons le nouveau générateur :
pnpm nx g @aws/nx-plugin:ts#trpc-api#procedureyarn nx g @aws/nx-plugin:ts#trpc-api#procedurenpx nx g @aws/nx-plugin:ts#trpc-api#procedurebunx nx g @aws/nx-plugin:ts#trpc-api#procedureVous pouvez également effectuer une simulation pour voir quels fichiers seraient modifiés
pnpm nx g @aws/nx-plugin:ts#trpc-api#procedure --dry-runyarn nx g @aws/nx-plugin:ts#trpc-api#procedure --dry-runnpx nx g @aws/nx-plugin:ts#trpc-api#procedure --dry-runbunx nx g @aws/nx-plugin:ts#trpc-api#procedure --dry-run- 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
En cas de succès, nous devrions avoir généré une nouvelle procédure et ajouté la procédure à notre routeur dans router.ts.
Exercices
Section intitulée « Exercices »Si vous êtes arrivé jusqu’ici et que vous 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
Section intitulée « 1. Opérations imbriquées »Essayez de mettre à jour le générateur pour prendre en charge les routeurs imbriqués en :
- Acceptant la notation par points pour l’entrée
procedure(par exemplegames.query) - Générant une procédure avec un nom basé sur la notation par points inversée (par exemple
queryGames) - Ajoutant le routeur imbriqué approprié (ou en le mettant à jour s’il existe déjà !)
2. Validation
Section intitulée « 2. Validation »Notre générateur devrait se défendre contre les problèmes potentiels, comme un utilisateur sélectionnant un project qui n’est pas une API tRPC. Jetez un œil au générateur connection pour un exemple de cela.
3. Tests unitaires
Section intitulée « 3. Tests unitaires »Écrivez quelques tests unitaires pour le générateur. Ceux-ci sont assez simples à implémenter, et la plupart suivent le flux général :
- Créer un arbre d’espace de travail vide en utilisant
createTreeUsingTsSolutionSetup() - Ajouter tous les fichiers qui devraient déjà exister dans l’arbre (par exemple
project.jsonetsrc/router.tspour un backend tRPC) - Exécuter le générateur testé
- Valider que les modifications attendues sont apportées à l’arbre
4. Tests de bout en bout
Section intitulée « 4. Tests de bout en bout »Nous avons une suite de “smoke tests” qui exécutent des générateurs dans un espace de travail frais et s’assurent que tout se construit. Au minimum, votre nouveau générateur devrait être ajouté aux deux matrices de générateurs afin qu’il soit exercé par les smoke tests :
e2e/src/smoke-tests/generator-matrix.ts— exécute chaque générateur via la CLI, une invocation à la fois, exactement comme le ferait un utilisateur.packages/nx-plugin/src/internal/test-matrix/generator.ts— un générateur caché qui compose tous les autres pour tester les migrations entre les versions.
Notez que la matrice de générateurs exécute uniquement les générateurs et construit l’espace de travail — elle n’instancie aucune infrastructure. Pour les générateurs qui déploient de l’infrastructure, envisagez d’étendre les tests e2e de déploiement (e2e/src/smoke-tests/cdk-deploy.spec.ts et terraform-deploy.spec.ts) pour déployer réellement vos ressources (via cdk deploy / terraform apply), puis ajoutez une assertion à deploy-invocations.ts qui invoque la ressource déployée et vérifie qu’elle se comporte comme prévu.
Si votre générateur fournit un serveur de développement local, envisagez de l’ajouter au test e2e de développement local (e2e/src/smoke-tests/local-dev.spec.ts), qui démarre la cible dev et exerce le serveur en cours d’exécution.
Conseils généraux pour accélérer la contribution
Section intitulée « Conseils généraux pour accélérer la contribution »Cette section contient quelques conseils généraux qui peuvent aider lors du travail sur le Nx Plugin for AWS.
Travailler à rebours à partir d’un projet réel
Section intitulée « Travailler à rebours à partir d’un projet réel »Une façon utile de créer de nouveaux générateurs ou d’ajouter des fonctionnalités/corrections à un générateur existant est de le construire d’abord pour de vrai. De cette façon, vous pouvez valider vos idées et itérer rapidement pour obtenir la fonctionnalité dont vous avez besoin. Après avoir établi le résultat souhaité, vous pouvez ensuite mettre à jour le générateur.
En pratique, ce processus pourrait ressembler à :
-
Créer un nouvel espace de travail
Terminal window pnpm create @aws/nx-workspace my-projectTerminal window yarn create @aws/nx-workspace my-projectTerminal window npm create @aws/nx-workspace -- my-projectTerminal window bun create @aws/nx-workspace my-project -
Exécuter tous les générateurs qui peuvent être des prérequis pour votre nouveau générateur/fonctionnalité/correction
-
Valider vos modifications (
git commit) -
Apporter vos modifications souhaitées et les tester selon les besoins
-
Utiliser le
git diffde vos modifications pour informer les modifications qui devraient être apportées au Nx Plugin for AWS -
Effectuer un dernier test de bout en bout (en liant votre
@aws/nx-plugin) pour vous assurer que votre générateur fournit les modifications dont vous avez besoin