Đóng góp một Generator
Hãy tạo một generator mới để đóng góp cho @aws/nx-plugin. Mục tiêu của chúng ta sẽ là tạo một procedure mới cho một tRPC API.
Kiểm tra Plugin
Phần tiêu đề “Kiểm tra Plugin”Đầu tiên, hãy clone plugin:
git clone git@github.com:awslabs/nx-plugin-for-aws.gitTiếp theo, cài đặt và build:
cd nx-plugin-for-awspnpm ipnpm nx run-many --target build --allTạo một Generator Trống
Phần tiêu đề “Tạo một Generator Trống”Hãy tạo generator mới trong packages/nx-plugin/src/trpc/procedure.
Chúng tôi cung cấp một generator để tạo các generator mới nên bạn có thể nhanh chóng scaffold generator mới của mình! Bạn có thể chạy generator này như sau:
- Install the Nx Console VSCode Plugin if you haven't already
- Open the Nx Console in VSCode
- Click
Generate (UI)in the "Common Nx Commands" section - Search for
@aws/nx-plugin - ts#nx-generator - Fill in the required parameters
- pluginProject: @aws/nx-plugin
- name: ts#trpc-api#procedure
- directory: trpc/procedure
- description: Adds a procedure to a tRPC API
- Click
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 APIyarn 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 APInpx 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 APIbunx 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 APIYou can also perform a dry-run to see what files would be changed
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-runyarn 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-runnpx 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-runbunx 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-runBạn sẽ nhận thấy các file sau đã được tạo cho bạn:
Thư mụcpackages/nx-plugin/src/trpc/procedure
- schema.json Định nghĩa đầu vào cho generator
- schema.d.ts Một interface typescript khớp với schema
- generator.ts Function mà Nx chạy như generator
- generator.spec.ts Tests cho generator
Thư mụcdocs/src/content/docs/guides/
- trpc-procedure.mdx Tài liệu cho generator
- packages/nx-plugin/generators.json Được cập nhật để bao gồm generator
Hãy cập nhật schema để thêm các thuộc tính chúng ta cần cho generator:
{ "$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';}Bạn sẽ nhận thấy generator đã được kết nối trong 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" } },...Triển khai Generator
Phần tiêu đề “Triển khai Generator”Để thêm một procedure vào tRPC API, chúng ta cần làm hai việc:
- Tạo một file TypeScript cho procedure mới
- Thêm procedure vào router
Tạo Procedure mới
Phần tiêu đề “Tạo Procedure mới”Để tạo file TypeScript cho procedure mới, chúng ta sẽ sử dụng một tiện ích gọi là generateFiles. Sử dụng công cụ này, chúng ta có thể định nghĩa một template EJS mà chúng ta có thể render trong generator với các biến dựa trên các options được người dùng chọn.
Đầu tiên, chúng ta sẽ định nghĩa template trong 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 {}; });Trong template, chúng ta đã tham chiếu ba biến:
procedureNameCamelCaseprocedureNameKebabCaseprocedureType
Vì vậy, chúng ta cần đảm bảo truyền những biến đó cho generateFiles, cũng như thư mục để tạo file vào, cụ thể là vị trí của các file nguồn (tức là sourceRoot) cho dự án tRPC mà người dùng đã chọn làm đầu vào cho generator, mà chúng ta có thể trích xuất từ cấu hình dự án.
Hãy cập nhật generator để làm điều đó:
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;Thêm Procedure vào Router
Phần tiêu đề “Thêm Procedure vào Router”Tiếp theo, chúng ta muốn generator kết nối procedure mới vào router. Điều này có nghĩa là đọc và cập nhật mã nguồn của người dùng!
Chúng ta sử dụng thao tác TypeScript AST để cập nhật các phần liên quan của file nguồn TypeScript. Có một số helper gọi là replace và destructuredImport để làm cho việc này dễ dàng hơn một chút.
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;Bây giờ chúng ta đã triển khai generator, hãy compile nó để đảm bảo nó có sẵn để chúng ta kiểm tra trong dự án dungeon adventure.
pnpm nx run @aws/nx-plugin:compileKiểm thử Generator
Phần tiêu đề “Kiểm thử Generator”Để kiểm thử generator, chúng ta sẽ liên kết Nx Plugin for AWS local của mình với một codebase hiện có.
Tạo một Dự án Test với tRPC API
Phần tiêu đề “Tạo một Dự án Test với tRPC API”Trong một thư mục riêng, tạo một test workspace mới:
npx create-nx-workspace@22.0.2 trpc-generator-test --pm=pnpm --preset=@aws/nx-plugin --ci=skip --aiAgentsnpx create-nx-workspace@22.0.2 trpc-generator-test --pm=yarn --preset=@aws/nx-plugin --ci=skip --aiAgentsnpx create-nx-workspace@22.0.2 trpc-generator-test --pm=npm --preset=@aws/nx-plugin --ci=skip --aiAgentsnpx create-nx-workspace@22.0.2 trpc-generator-test --pm=bun --preset=@aws/nx-plugin --ci=skip --aiAgentsTiếp theo, hãy tạo một tRPC API để thêm procedure vào:
- Install the Nx Console VSCode Plugin if you haven't already
- Open the Nx Console in VSCode
- Click
Generate (UI)in the "Common Nx Commands" section - Search for
@aws/nx-plugin - ts#trpc-api - Fill in the required parameters
- apiName: test-api
- Click
Generate
pnpm nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactiveyarn nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactivenpx nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactivebunx nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactiveYou can also perform a dry-run to see what files would be changed
pnpm nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive --dry-runyarn nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive --dry-runnpx nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive --dry-runbunx nx g @aws/nx-plugin:ts#trpc-api --apiName=test-api --no-interactive --dry-runLiên kết Nx Plugin for AWS local của chúng ta
Phần tiêu đề “Liên kết Nx Plugin for AWS local của chúng ta”Trong codebase của bạn, hãy liên kết @aws/nx-plugin local của chúng ta:
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-pluginChạy Generator mới
Phần tiêu đề “Chạy Generator mới”Hãy thử generator mới:
- Install the Nx Console VSCode Plugin if you haven't already
- Open the Nx Console in VSCode
- Click
Generate (UI)in the "Common Nx Commands" section - Search for
@aws/nx-plugin - ts#trpc-api#procedure - Fill in the required parameters
- Click
Generate
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#procedureYou can also perform a dry-run to see what files would be changed
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-runNếu thành công, chúng ta đã tạo một procedure mới và thêm procedure vào router của chúng ta trong router.ts.
Bài tập
Phần tiêu đề “Bài tập”Nếu bạn đã đến đây và vẫn còn thời gian để thử nghiệm với Nx generators, đây là một số gợi ý về các tính năng để thêm vào procedure generator:
1. Nested Operations
Phần tiêu đề “1. Nested Operations”Thử cập nhật generator để hỗ trợ nested routers bằng cách:
- Chấp nhận ký hiệu dấu chấm cho đầu vào
procedure(ví dụ:games.query) - Tạo một procedure với tên dựa trên ký hiệu dấu chấm đảo ngược (ví dụ:
queryGames) - Thêm nested router thích hợp (hoặc cập nhật nó nếu nó đã tồn tại!)
2. Validation
Phần tiêu đề “2. Validation”Generator của chúng ta nên bảo vệ chống lại các vấn đề tiềm ẩn, chẳng hạn như người dùng chọn một project không phải là tRPC API. Hãy xem generator api-connection để xem ví dụ về điều này.
3. Unit Tests
Phần tiêu đề “3. Unit Tests”Viết một số unit tests cho generator. Chúng khá đơn giản để triển khai, và hầu hết tuân theo luồng chung:
- Tạo một empty workspace tree bằng cách sử dụng
createTreeUsingTsSolutionSetup() - Thêm bất kỳ file nào đã tồn tại trong tree (ví dụ:
project.jsonvàsrc/router.tscho tRPC backend) - Chạy generator đang được kiểm thử
- Xác thực các thay đổi mong đợi được thực hiện đối với tree
4. End to End Tests
Phần tiêu đề “4. End to End Tests”Hiện tại, chúng ta có một “smoke test” duy nhất chạy tất cả các generators và đảm bảo rằng build thành công. Điều này nên được cập nhật để bao gồm generator mới.