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
Section intitulée « 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
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, 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
Section intitulée « 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
Section intitulée « 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
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 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
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 nouveau workspace de 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
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
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-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
Section intitulée « 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
Section intitulée « 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
Section intitulée « 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
Section intitulée « 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
Section intitulée « 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
Section intitulée « 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.