Contribuir un Generador
Vamos a crear un nuevo generador para contribuir a @aws/nx-plugin. Nuestro objetivo será generar un nuevo procedimiento para una API tRPC.
Clonar el Plugin
Sección titulada «Clonar el Plugin»Primero, clonemos el plugin:
git clone git@github.com:awslabs/nx-plugin-for-aws.gitA continuación, instala y compila:
cd nx-plugin-for-awspnpm ipnpm nx run-many --target build --allCrear un Generador Vacío
Sección titulada «Crear un Generador Vacío»Vamos a crear el nuevo generador en packages/nx-plugin/src/trpc/procedure.
¡Proporcionamos un generador para crear nuevos generadores para que puedas estructurar rápidamente tu nuevo generador! Puedes ejecutar este generador de la siguiente manera:
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 APITambién puede realizar una ejecución en seco para ver qué archivos se cambiarían
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- Instale el Nx Console VSCode Plugin si aún no lo ha hecho
- Abra la consola Nx en VSCode
- Haga clic en
Generate (UI)en la sección "Common Nx Commands" - Busque
@aws/nx-plugin - ts#nx-generator - Complete los parámetros requeridos
- project: @aws/nx-plugin
- name: ts#trpc-api#procedure
- directory: trpc/procedure
- description: Adds a procedure to a tRPC API
- Haga clic en
Generate
Notarás que se han generado los siguientes archivos para ti:
Directoriopackages/nx-plugin/src/trpc/procedure
- schema.json Define la entrada para el generador
- schema.d.ts Una interfaz de typescript que coincide con el esquema
- generator.ts Función que Nx ejecuta como el generador
- generator.spec.ts Pruebas para el generador
Directoriodocs/src/content/docs/guides/
- trpc-procedure.mdx Documentación para el generador
- packages/nx-plugin/generators.json Actualizado para incluir el generador
Actualicemos el esquema para agregar las propiedades que necesitaremos para el generador:
{ "$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';}Notarás que el generador ya ha sido conectado en 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" } },...Implementar el Generador
Sección titulada «Implementar el Generador»Para agregar un procedimiento a una API tRPC, necesitamos hacer dos cosas:
- Crear un archivo TypeScript para el nuevo procedimiento
- Agregar el procedimiento al router
Crear el nuevo Procedimiento
Sección titulada «Crear el nuevo Procedimiento»Para crear el archivo TypeScript para el nuevo procedimiento, usaremos una utilidad llamada generateFiles. Con esto, podemos definir una plantilla EJS que podemos renderizar en nuestro generador con variables basadas en las opciones seleccionadas por el usuario.
Primero, definiremos la plantilla en 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 {}; });En la plantilla, referenciamos tres variables:
procedureNameCamelCaseprocedureNameKebabCaseprocedureType
Así que necesitaremos asegurarnos de pasar esas a generateFiles, así como el directorio donde generar archivos, es decir, la ubicación de los archivos fuente (i.e. sourceRoot) para el proyecto tRPC que el usuario seleccionó como entrada para el generador, que podemos extraer de la configuración del proyecto.
Actualicemos el generador para hacer eso:
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;Agregar el Procedimiento al Router
Sección titulada «Agregar el Procedimiento al Router»A continuación, queremos que el generador conecte el nuevo procedimiento al router. ¡Esto significa leer y actualizar el código fuente del usuario!
Usamos GritQL para buscar y transformar código fuente de manera declarativa. El helper addDestructuredImport agrega importaciones nombradas, y applyGritQL aplica un patrón GritQL para agregar el procedimiento al objeto literal del router.
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;Ahora que hemos implementado el generador, compilémoslo para asegurarnos de que esté disponible para probarlo en nuestro proyecto de aventura en mazmorras.
pnpm nx compile @aws/nx-pluginProbar el Generador
Sección titulada «Probar el Generador»Para probar el generador, vincularemos nuestro Nx Plugin for AWS local a una base de código existente.
Crear un Proyecto de Prueba con una API tRPC
Sección titulada «Crear un Proyecto de Prueba con una API tRPC»En un directorio separado, crea un nuevo workspace de prueba:
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-testA continuación, generemos una API tRPC para agregar el procedimiento:
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-interactiveTambién puede realizar una ejecución en seco para ver qué archivos se cambiarían
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- Instale el Nx Console VSCode Plugin si aún no lo ha hecho
- Abra la consola Nx en VSCode
- Haga clic en
Generate (UI)en la sección "Common Nx Commands" - Busque
@aws/nx-plugin - ts#api - Complete los parámetros requeridos
- name: test-api
- framework: trpc
- Haga clic en
Generate
Vincular nuestro Nx Plugin for AWS local
Sección titulada «Vincular nuestro Nx Plugin for AWS local»En tu base de código, vinculemos nuestro @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-pluginEjecutar el nuevo Generador
Sección titulada «Ejecutar el nuevo Generador»Probemos el nuevo generador:
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#procedureTambién puede realizar una ejecución en seco para ver qué archivos se cambiarían
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- Instale el Nx Console VSCode Plugin si aún no lo ha hecho
- Abra la consola Nx en VSCode
- Haga clic en
Generate (UI)en la sección "Common Nx Commands" - Busque
@aws/nx-plugin - ts#trpc-api#procedure - Complete los parámetros requeridos
- Haga clic en
Generate
Si tiene éxito, deberíamos haber generado un nuevo procedimiento y agregado el procedimiento a nuestro router en router.ts.
Ejercicios
Sección titulada «Ejercicios»Si has llegado hasta aquí y aún tienes algo de tiempo para experimentar con generadores Nx, aquí hay algunas sugerencias de características para agregar al generador de procedimientos:
1. Operaciones Anidadas
Sección titulada «1. Operaciones Anidadas»Intenta actualizar el generador para soportar routers anidados mediante:
- Aceptar notación de puntos para la entrada
procedure(por ejemplo,games.query) - Generar un procedimiento con un nombre basado en notación de puntos invertida (por ejemplo,
queryGames) - Agregar el router anidado apropiado (¡o actualizarlo si ya existe!)
2. Validación
Sección titulada «2. Validación»Nuestro generador debería defenderse contra problemas potenciales, como que un usuario seleccione un project que no sea una API tRPC. Echa un vistazo al generador connection para ver un ejemplo de esto.
3. Pruebas Unitarias
Sección titulada «3. Pruebas Unitarias»Escribe algunas pruebas unitarias para el generador. Estas son bastante sencillas de implementar, y la mayoría siguen el flujo general:
- Crear un árbol de workspace vacío usando
createTreeUsingTsSolutionSetup() - Agregar cualquier archivo que ya debería existir en el árbol (por ejemplo,
project.jsonysrc/router.tspara un backend tRPC) - Ejecutar el generador bajo prueba
- Validar que se realicen los cambios esperados en el árbol
4. Pruebas de Extremo a Extremo
Sección titulada «4. Pruebas de Extremo a Extremo»Tenemos un conjunto de “smoke tests” que ejecutan generadores en un workspace nuevo y se aseguran de que todo compile. Como mínimo, tu nuevo generador debería agregarse a ambas matrices de generadores para que sea ejercitado por los smoke tests:
e2e/src/smoke-tests/generator-matrix.ts— ejecuta cada generador a través del CLI, una invocación a la vez, exactamente como lo haría un usuario.packages/nx-plugin/src/internal/test-matrix/generator.ts— un generador oculto que compone todos los demás para probar migraciones entre versiones.
Ten en cuenta que la matriz de generadores solo ejecuta los generadores y compila el workspace; no instancia ninguna infraestructura. Para generadores que despliegan infraestructura, considera extender las pruebas e2e de despliegue (e2e/src/smoke-tests/cdk-deploy.spec.ts y terraform-deploy.spec.ts) para realmente desplegar tus recursos (a través de cdk deploy / terraform apply), luego agrega una aserción a deploy-invocations.ts que invoque el recurso desplegado y verifique que se comporte como se espera.
Si tu generador proporciona un servidor de desarrollo local, considera agregarlo a la prueba e2e de desarrollo local (e2e/src/smoke-tests/local-dev.spec.ts), que inicia el target dev y ejercita el servidor en ejecución.
Orientación General para Acelerar la Contribución
Sección titulada «Orientación General para Acelerar la Contribución»Esta sección contiene orientación general que puede ayudar al trabajar en el Nx Plugin for AWS.
Trabajar hacia atrás desde un proyecto real
Sección titulada «Trabajar hacia atrás desde un proyecto real»Una forma útil de construir nuevos generadores o agregar características/correcciones a un generador existente es construirlo primero de verdad. De esta manera puedes validar tus ideas e iterar rápidamente para lograr la funcionalidad que necesitas. Después de que hayas decidido el resultado deseado, puedes actualizar el generador.
En la práctica, este proceso podría verse así:
-
Crear un nuevo workspace
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 -
Ejecutar cualquier generador que pueda ser un requisito previo para tu nuevo generador/característica/corrección
-
Confirmar tus cambios (
git commit) -
Hacer los cambios deseados y probarlos según sea necesario
-
Usar el
git diffde tus cambios para informar qué cambios deben hacerse al Nx Plugin for AWS -
Realizar una prueba final de extremo a extremo (vinculando tu
@aws/nx-plugin) para asegurar que tu generador proporcione los cambios que necesitas