Contribuir com um Gerador
Vamos criar um novo gerador para contribuir com o @aws/nx-plugin. Nosso objetivo será gerar um novo procedimento para uma API tRPC.
Fazer Checkout do Plugin
Seção intitulada “Fazer Checkout do Plugin”Primeiro, vamos clonar o plugin:
git clone git@github.com:awslabs/nx-plugin-for-aws.gitEm seguida, instale e compile:
cd nx-plugin-for-awspnpm ipnpm nx run-many --target build --allCriar um Gerador Vazio
Seção intitulada “Criar um Gerador Vazio”Vamos criar o novo gerador em packages/nx-plugin/src/trpc/procedure.
Fornecemos um gerador para criar novos geradores para que você possa rapidamente estruturar seu novo gerador! Você pode executar este gerador da seguinte forma:
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 APIVocê também pode realizar uma execução simulada para ver quais arquivos seriam alterados
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 o Nx Console VSCode Plugin se ainda não o fez
- Abra o console Nx no VSCode
- Clique em
Generate (UI)na seção "Common Nx Commands" - Procure por
@aws/nx-plugin - ts#nx-generator - Preencha os parâmetros obrigatórios
- project: @aws/nx-plugin
- name: ts#trpc-api#procedure
- directory: trpc/procedure
- description: Adds a procedure to a tRPC API
- Clique em
Generate
Você notará que os seguintes arquivos foram gerados para você:
Directorypackages/nx-plugin/src/trpc/procedure
- schema.json Define a entrada para o gerador
- schema.d.ts Uma interface typescript que corresponde ao schema
- generator.ts Função que o Nx executa como o gerador
- generator.spec.ts Testes para o gerador
Directorydocs/src/content/docs/guides/
- trpc-procedure.mdx Documentação para o gerador
- packages/nx-plugin/generators.json Atualizado para incluir o gerador
Vamos atualizar o schema para adicionar as propriedades que precisaremos para o gerador:
{ "$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';}Você notará que o gerador já foi conectado em 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 o Gerador
Seção intitulada “Implementar o Gerador”Para adicionar um procedimento a uma API tRPC, precisamos fazer duas coisas:
- Criar um arquivo TypeScript para o novo procedimento
- Adicionar o procedimento ao roteador
Criar o novo Procedimento
Seção intitulada “Criar o novo Procedimento”Para criar o arquivo TypeScript para o novo procedimento, usaremos um utilitário chamado generateFiles. Usando isso, podemos definir um template EJS que podemos renderizar em nosso gerador com variáveis baseadas nas opções selecionadas pelo usuário.
Primeiro, definiremos o template em 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 {}; });No template, referenciamos três variáveis:
procedureNameCamelCaseprocedureNameKebabCaseprocedureType
Então precisaremos garantir que passamos essas para generateFiles, assim como o diretório para gerar arquivos, ou seja, a localização dos arquivos fonte (i.e. sourceRoot) para o projeto tRPC que o usuário selecionou como entrada para o gerador, que podemos extrair da configuração do projeto.
Vamos atualizar o gerador para fazer isso:
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;Adicionar o Procedimento ao Roteador
Seção intitulada “Adicionar o Procedimento ao Roteador”Em seguida, queremos que o gerador conecte o novo procedimento ao roteador. Isso significa ler e atualizar o código fonte do usuário!
Usamos GritQL para buscar e transformar código fonte de forma declarativa. O helper addDestructuredImport adiciona imports nomeados, e applyGritQL aplica um padrão GritQL para adicionar o procedimento ao objeto literal do roteador.
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;Agora que implementamos o gerador, vamos compilá-lo para garantir que esteja disponível para testarmos em nosso projeto de aventura na masmorra.
pnpm nx compile @aws/nx-pluginTestando o Gerador
Seção intitulada “Testando o Gerador”Para testar o gerador, vamos vincular nosso Nx Plugin for AWS local a uma base de código existente.
Criar um Projeto de Teste com uma API tRPC
Seção intitulada “Criar um Projeto de Teste com uma API tRPC”Em um diretório separado, crie um novo workspace de teste:
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-testEm seguida, vamos gerar uma API tRPC para adicionar o procedimento:
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-interactiveVocê também pode realizar uma execução simulada para ver quais arquivos seriam alterados
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 o Nx Console VSCode Plugin se ainda não o fez
- Abra o console Nx no VSCode
- Clique em
Generate (UI)na seção "Common Nx Commands" - Procure por
@aws/nx-plugin - ts#api - Preencha os parâmetros obrigatórios
- name: test-api
- framework: trpc
- Clique em
Generate
Vincular nosso Nx Plugin for AWS local
Seção intitulada “Vincular nosso Nx Plugin for AWS local”Em sua base de código, vamos vincular nosso @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-pluginExecutar o novo Gerador
Seção intitulada “Executar o novo Gerador”Vamos experimentar o novo gerador:
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#procedureVocê também pode realizar uma execução simulada para ver quais arquivos seriam alterados
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 o Nx Console VSCode Plugin se ainda não o fez
- Abra o console Nx no VSCode
- Clique em
Generate (UI)na seção "Common Nx Commands" - Procure por
@aws/nx-plugin - ts#trpc-api#procedure - Preencha os parâmetros obrigatórios
- Clique em
Generate
Se bem-sucedido, devemos ter gerado um novo procedimento e adicionado o procedimento ao nosso roteador em router.ts.
Exercícios
Seção intitulada “Exercícios”Se você chegou até aqui e ainda tem algum tempo para experimentar com geradores Nx, aqui estão algumas sugestões de recursos para adicionar ao gerador de procedimentos:
1. Operações Aninhadas
Seção intitulada “1. Operações Aninhadas”Tente atualizar o gerador para suportar roteadores aninhados:
- Aceitando notação de ponto para a entrada
procedure(por exemplo,games.query) - Gerando um procedimento com um nome baseado em notação de ponto reversa (por exemplo,
queryGames) - Adicionando o roteador aninhado apropriado (ou atualizando-o se já existir!)
2. Validação
Seção intitulada “2. Validação”Nosso gerador deve se defender contra problemas potenciais, como um usuário selecionando um project que não é uma API tRPC. Dê uma olhada no gerador connection para um exemplo disso.
3. Testes Unitários
Seção intitulada “3. Testes Unitários”Escreva alguns testes unitários para o gerador. Eles são bastante diretos de implementar, e a maioria segue o fluxo geral:
- Criar uma árvore de workspace vazia usando
createTreeUsingTsSolutionSetup() - Adicionar quaisquer arquivos que já devem existir na árvore (por exemplo,
project.jsonesrc/router.tspara um backend tRPC) - Executar o gerador em teste
- Validar que as alterações esperadas são feitas na árvore
4. Testes End to End
Seção intitulada “4. Testes End to End”Temos uma suíte de “smoke tests” que executam geradores em um workspace novo e garantem que tudo compila. No mínimo, seu novo gerador deve ser adicionado a ambas as matrizes de geradores para que seja exercitado pelos smoke tests:
e2e/src/smoke-tests/generator-matrix.ts— executa cada gerador através da CLI, uma invocação por vez, exatamente como um usuário faria.packages/nx-plugin/src/internal/test-matrix/generator.ts— um gerador oculto que compõe todos os outros para testar migrações entre versões.
Observe que a matriz de geradores apenas executa os geradores e compila o workspace — ela não instancia nenhuma infraestrutura. Para geradores que implantam infraestrutura, considere estender os testes e2e de implantação (e2e/src/smoke-tests/cdk-deploy.spec.ts e terraform-deploy.spec.ts) para realmente implantar seus recursos (via cdk deploy / terraform apply), depois adicione uma asserção a deploy-invocations.ts que invoca o recurso implantado e verifica se ele se comporta como esperado.
Se seu gerador fornece um servidor de desenvolvimento local, considere adicioná-lo ao teste e2e de desenvolvimento local (e2e/src/smoke-tests/local-dev.spec.ts), que inicia o target dev e exercita o servidor em execução.
Orientação Geral para Acelerar a Contribuição
Seção intitulada “Orientação Geral para Acelerar a Contribuição”Esta seção contém algumas orientações gerais que podem ajudar ao trabalhar no Nx Plugin for AWS.
Trabalhe de trás para frente a partir de um projeto real
Seção intitulada “Trabalhe de trás para frente a partir de um projeto real”Uma maneira útil de construir novos geradores ou adicionar recursos/correções a um gerador existente é construí-lo de verdade primeiro. Dessa forma, você pode validar suas ideias e iterar rapidamente para alcançar a funcionalidade que precisa. Depois de ter decidido sobre o resultado desejado, você pode então atualizar o gerador.
Na prática, este processo pode parecer com:
-
Criar um novo 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 -
Executar quaisquer geradores que possam ser pré-requisitos para seu novo gerador/recurso/correção
-
Fazer commit de suas alterações (
git commit) -
Fazer suas alterações desejadas e testá-las conforme necessário
-
Usar o
git diffde suas alterações para informar quais alterações devem ser feitas no Nx Plugin for AWS -
Realizar um teste final end to end (vinculando seu
@aws/nx-plugin) para garantir que seu gerador forneça as alterações que você precisa