Contribua 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.
Confira o Plugin
Seção intitulada “Confira o Plugin”Primeiro, vamos clonar o plugin:
git clone git@github.com:awslabs/nx-plugin-for-aws.git
Em seguida, instale e construa:
cd nx-plugin-for-awspnpm ipnpm nx run-many --target build --all
Crie um Gerador Vazio
Seção intitulada “Crie um Gerador Vazio”Vamos criar o novo gerador em packages/nx-plugin/src/trpc/procedure
.
Fornecemos um gerador para criar novos geradores, permitindo que você scaffold seu novo gerador rapidamente! Você pode executar este gerador da seguinte forma:
- 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
- pluginProject: @aws/nx-plugin
- name: ts#trpc-api#procedure
- directory: trpc/procedure
- description: Adds a procedure to a tRPC API
- Clique em
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
Você também pode realizar uma execução simulada para ver quais arquivos seriam alterados
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
Você notará que os seguintes arquivos foram gerados para você:
Directorypackages/nx-plugin/src/trpc/procedure
- schema.json Define a entrada do gerador
- schema.d.ts Uma interface TypeScript que corresponde ao schema
- generator.ts Função executada pelo Nx como gerador
- generator.spec.ts Testes para o gerador
Directorydocs/src/content/docs/guides/
- trpc-procedure.mdx Documentação do gerador
- packages/nx-plugin/generators.json Atualizado para incluir o gerador
Vamos atualizar o schema para adicionar as propriedades necessárias ao 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" } },...
Implemente o Gerador
Seção intitulada “Implemente 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 router
Crie o Novo Procedimento
Seção intitulada “Crie o Novo Procedimento”Para criar o arquivo TypeScript do novo procedimento, usaremos um utilitário chamado generateFiles
. Com ele, podemos definir um template EJS que será renderizado 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/v4';
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:
procedureNameCamelCase
procedureNameKebabCase
procedureType
Precisamos garantir que passamos essas variáveis para o generateFiles
, bem como o diretório para gerar os arquivos, ou seja, o local dos arquivos fonte (ex: sourceRoot
) do projeto tRPC selecionado pelo usuário como entrada do gerador, que podemos extrair da configuração do projeto.
Vamos atualizar o gerador para fazer isso:
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;
Adicione o Procedimento ao Router
Seção intitulada “Adicione o Procedimento ao Router”Em seguida, queremos que o gerador conecte o novo procedimento ao router. Isso significa ler e atualizar o código fonte do usuário!
Usamos manipulação de AST do TypeScript para atualizar as partes relevantes do arquivo fonte. Existem helpers chamados replace
e destructuredImport
para facilitar isso.
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;
Agora que implementamos o gerador, vamos compilá-lo para garantir que esteja disponível para testarmos em nosso projeto de aventura no calabouço.
pnpm nx run @aws/nx-plugin:compile
Testando o Gerador
Seção intitulada “Testando o Gerador”Para testar o gerador, vincularemos nosso Nx Plugin for AWS local a uma codebase existente.
Crie um Projeto de Teste com uma API tRPC
Seção intitulada “Crie um Projeto de Teste com uma API tRPC”Em um diretório separado, crie um novo workspace de teste:
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
Em seguida, vamos gerar uma API tRPC para adicionar o procedimento:
- 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
- Preencha os parâmetros obrigatórios
- apiName: test-api
- Clique em
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
Você também pode realizar uma execução simulada para ver quais arquivos seriam alterados
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
Vincule nosso Nx Plugin for AWS local
Seção intitulada “Vincule nosso Nx Plugin for AWS local”Em sua codebase, vamos vincular nosso @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
Execute o Novo Gerador
Seção intitulada “Execute o Novo Gerador”Vamos testar o novo gerador:
- 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
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
Você 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-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
Se bem-sucedido, devemos ter gerado um novo procedimento e adicionado o procedimento ao nosso router em router.ts
.
Exercícios
Seção intitulada “Exercícios”Se você chegou até aqui e ainda tem tempo para experimentar com geradores Nx, aqui estão algumas sugestões de funcionalidades para adicionar ao gerador de procedimentos:
1. Operações Aninhadas
Seção intitulada “1. Operações Aninhadas”Tente atualizar o gerador para suportar routers aninhados:
- Aceitando notação de ponto para a entrada
procedure
(ex:games.query
) - Gerando um procedimento com nome baseado na notação de ponto invertida (ex:
queryGames
) - Adicionando o router aninhado apropriado (ou atualizando-o se já existir!)
2. Validação
Seção intitulada “2. Validação”Nosso gerador deve prevenir problemas potenciais, como um usuário selecionar um project
que não é uma API tRPC. Veja o gerador api-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 relativamente simples de implementar e seguem o fluxo geral:
- Criar uma workspace tree vazia usando
createTreeUsingTsSolutionSetup()
- Adicionar quaisquer arquivos que já devem existir na tree (ex:
project.json
esrc/router.ts
para um backend tRPC) - Executar o gerador em teste
- Validar que as alterações esperadas foram feitas na tree
4. Testes End to End
Seção intitulada “4. Testes End to End”Atualmente, temos um único “smoke test” que executa todos os geradores e verifica se a build é bem-sucedida. Isso deve ser atualizado para incluir o novo gerador.