생성기 기여하기
@aws/nx-plugin
에 기여할 새로운 제너레이터를 생성해 보겠습니다. 목표는 tRPC API를 위한 새로운 프로시저를 생성하는 것입니다.
플러그인 확인
섹션 제목: “플러그인 확인”먼저 플러그인을 클론합니다:
git clone git@github.com:awslabs/nx-plugin-for-aws.git
그런 다음 설치 및 빌드:
cd nx-plugin-for-awspnpm ipnpm nx run-many --target build --all
빈 제너레이터 생성
섹션 제목: “빈 제너레이터 생성”새 제너레이터를 packages/nx-plugin/src/trpc/procedure
에 생성합니다.
새 제너레이터를 빠르게 스캐폴딩할 수 있도록 제너레이터 생성용 제너레이터를 제공합니다! 다음 명령으로 실행할 수 있습니다:
- 설치 Nx Console VSCode Plugin 아직 설치하지 않았다면
- VSCode에서 Nx 콘솔 열기
- 클릭
Generate (UI)
"Common Nx Commands" 섹션에서 - 검색
@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
- 클릭
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
어떤 파일이 변경될지 확인하기 위해 드라이 런을 수행할 수도 있습니다
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
다음 파일들이 자동 생성됩니다:
디렉터리packages/nx-plugin/src/trpc/procedure
- schema.json 제너레이터 입력 정의
- schema.d.ts 스키마와 일치하는 타입스크립트 인터페이스
- generator.ts Nx가 실행하는 제너레이터 함수
- generator.spec.ts 제너레이터 테스트
디렉터리docs/src/content/docs/guides/
- trpc-procedure.mdx 제너레이터 문서
- packages/nx-plugin/generators.json 제너레이터 포함되도록 업데이트
제너레이터에 필요한 속성을 스키마에 추가합니다:
{ "$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';}
:::참고
제너레이터는 입력으로 Tree
와 스키마에 정의된 옵션을 받습니다. Tree
는 가상 파일 시스템으로, 프로젝트 파일을 생성하거나 업데이트하기 위해 읽고 쓸 수 있습니다. 사용자가 “dry-run” 모드로 제너레이터를 실행할 때 파일 시스템을 직접 건드리지 않기 위해 사용합니다.
:::
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" } },...
제너레이터 구현
섹션 제목: “제너레이터 구현”tRPC API에 프로시저를 추가하려면 두 가지가 필요합니다:
- 새 프로시저용 타입스크립트 파일 생성
- 라우터에 프로시저 추가
새 프로시저 생성
섹션 제목: “새 프로시저 생성”generateFiles
유틸리티를 사용해 EJS 템플릿을 렌더링합니다. 사용자가 선택한 옵션을 기반으로 변수를 전달합니다.
템플릿을 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: 입력 정의 })) .output(z.object({ // TODO: 출력 정의 })) .<%- procedureType %>(async ({ input, ctx }) => { // TODO: 구현! return {}; });
:::팁
generateFiles
는 파일/디렉토리 이름의 __<변수>__
를 제공된 값으로 대체하고 .template
확장자를 제거합니다. 템플릿 내용은 <% ... %>
구문을 사용하는 EJS입니다.
:::
템플릿에서 세 가지 변수를 참조했습니다:
procedureNameCamelCase
procedureNameKebabCase
procedureType
이 변수들을 generateFiles
에 전달하고, 사용자가 선택한 프로젝트의 소스 루트 경로를 추출합니다:
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;
:::팁
formatFilesInSubtree
를 호출해 생성/수정된 파일들을 사용자의 Prettier 설정에 따라 포맷팅합니다.
:::
라우터에 프로시저 추가
섹션 제목: “라우터에 프로시저 추가”TypeScript AST 조작을 통해 소스 코드를 업데이트합니다. replace
와 destructuredImport
헬퍼를 사용합니다:
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;
:::팁
replace
는 tsquery 셀렉터를 사용해 router
함수의 인자를 찾습니다. tsquery 플레이그라운드에서 셀렉터를 테스트할 수 있습니다.
:::
제너레이터 구현 후 컴파일하여 테스트 준비:
pnpm nx run @aws/nx-plugin:compile
제너레이터 테스트
섹션 제목: “제너레이터 테스트”로컬 Nx 플러그인을 기존 코드베이스에 연결하여 테스트합니다.
tRPC API가 있는 테스트 프로젝트 생성
섹션 제목: “tRPC API가 있는 테스트 프로젝트 생성”:::참고 던전 어드벤처 튜토리얼을 완료했거나 tRPC API를 사용하는 기존 Nx 워크스페이스가 있다면 이 단계를 건너뛸 수 있습니다. :::
새 테스트 워크스페이스 생성:
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
tRPC API 생성:
- 설치 Nx Console VSCode Plugin 아직 설치하지 않았다면
- VSCode에서 Nx 콘솔 열기
- 클릭
Generate (UI)
"Common Nx Commands" 섹션에서 - 검색
@aws/nx-plugin - ts#trpc-api
- 필수 매개변수 입력
- apiName: test-api
- 클릭
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
어떤 파일이 변경될지 확인하기 위해 드라이 런을 수행할 수도 있습니다
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
로컬 Nx 플러그인 연결
섹션 제목: “로컬 Nx 플러그인 연결”로컬 @aws/nx-plugin
연결:
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
:::참고
소스 코드 대신 dist/packages/nx-plugin
의 컴파일된 플러그인을 연결합니다.
:::
새 제너레이터 실행
섹션 제목: “새 제너레이터 실행”새 제너레이터 실행 시도:
- 설치 Nx Console VSCode Plugin 아직 설치하지 않았다면
- VSCode에서 Nx 콘솔 열기
- 클릭
Generate (UI)
"Common Nx Commands" 섹션에서 - 검색
@aws/nx-plugin - ts#trpc-api#procedure
- 필수 매개변수 입력
- 클릭
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
어떤 파일이 변경될지 확인하기 위해 드라이 런을 수행할 수도 있습니다
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
:::참고 VSCode에서 새 제너레이터가 보이지 않으면 Nx 워크스페이스를 새로고침:
pnpm nx reset
yarn nx reset
npx nx reset
bunx nx reset
:::
성공하면 새 프로시저가 생성되고 router.ts
에 추가됩니다.
연습 문제
섹션 제목: “연습 문제”추가 실습을 위한 제안 사항:
1. 중첩 작업 지원
섹션 제목: “1. 중첩 작업 지원”procedure
입력에 점 표기법 지원 (예:games.query
)- 역방향 점 표기법 기반 프로시저 이름 생성 (예:
queryGames
) - 중첩 라우터 생성/업데이트
2. 유효성 검사
섹션 제목: “2. 유효성 검사”tRPC API가 아닌 프로젝트 선택 방지. api-connection
제너레이터 예제 참조.
3. 단위 테스트 작성
섹션 제목: “3. 단위 테스트 작성”테스트 흐름:
createTreeUsingTsSolutionSetup()
로 빈 워크스페이스 생성- 기존 파일 추가 (예:
project.json
,src/router.ts
) - 제너레이터 실행
- 트리 변경 사항 검증
4. 종단 간 테스트
섹션 제목: “4. 종단 간 테스트”현재 “smoke test”가 모든 제너레이터 실행 및 빌드 성공을 확인합니다. 새 제너레이터를 포함하도록 업데이트 필요.