Nx Generator Generator
Thêm một Nx Generator vào dự án TypeScript, giúp bạn tự động hóa các tác vụ lặp đi lặp lại như tạo scaffold cho các component hoặc thực thi các cấu trúc dự án cụ thể.
Cách sử dụng
Phần tiêu đề “Cách sử dụng”Tạo một Generator
Phần tiêu đề “Tạo một Generator”Bạn có thể tạo một generator theo hai cách:
- Cài đặt Nx Console VSCode Plugin nếu bạn chưa cài đặt
- Mở Nx Console trong VSCode
- Nhấp
Generate (UI)trong phần "Common Nx Commands" - Tìm kiếm
@aws/nx-plugin - ts#nx-generator - Điền các tham số bắt buộc
- Nhấp
Generate
pnpm nx g @aws/nx-plugin:ts#nx-generatoryarn nx g @aws/nx-plugin:ts#nx-generatornpx nx g @aws/nx-plugin:ts#nx-generatorbunx nx g @aws/nx-plugin:ts#nx-generatorBạn cũng có thể thực hiện chạy thử để xem những tệp nào sẽ bị thay đổi
pnpm nx g @aws/nx-plugin:ts#nx-generator --dry-runyarn nx g @aws/nx-plugin:ts#nx-generator --dry-runnpx nx g @aws/nx-plugin:ts#nx-generator --dry-runbunx nx g @aws/nx-plugin:ts#nx-generator --dry-runTùy chọn
Phần tiêu đề “Tùy chọn”| Tham số | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
| project Bắt buộc | string | - | Dự án TypeScript để thêm generator vào. Chúng tôi khuyến nghị sử dụng generator ts#nx-plugin để tạo dự án này. |
| name Bắt buộc | string | - | Tên generator |
| description | string | - | Mô tả về generator của bạn |
| directory | string | - | Thư mục trong thư mục nguồn của dự án plugin để thêm generator vào (mặc định: <name>) |
Kết quả của Generator
Phần tiêu đề “Kết quả của Generator”Generator sẽ tạo các tệp dự án sau trong project đã cho:
Thư mụcsrc/<name>/
- schema.json Schema cho đầu vào của generator
- schema.d.ts Các kiểu TypeScript cho schema
- generator.ts Triển khai generator cơ bản
- generator.spec.ts Các bài kiểm tra cho generator
- README.md Tài liệu cho generator
- generators.json Cấu hình Nx để định nghĩa các generator
- package.json Được tạo hoặc cập nhật để thêm mục “generators”
- tsconfig.json Được cập nhật để sử dụng CommonJS
Sửa đổi dự án
Generator này sẽ cập nhật project đã chọn để sử dụng CommonJS, vì Nx Generators hiện chỉ hỗ trợ CommonJS (tham khảo GitHub issue này để biết về hỗ trợ ESM).
Generators Cục bộ
Phần tiêu đề “Generators Cục bộ”Chọn dự án nx-plugin cục bộ của bạn khi chạy generator ts#nx-generator, và chỉ định tên cùng với thư mục và mô tả tùy chọn.
Định nghĩa Schema
Phần tiêu đề “Định nghĩa Schema”Tệp schema.json định nghĩa các tùy chọn mà generator của bạn chấp nhận. Nó tuân theo định dạng JSON Schema với các phần mở rộng đặc biệt của Nx.
Cấu trúc Cơ bản
Phần tiêu đề “Cấu trúc Cơ bản”Một tệp schema.json có cấu trúc cơ bản như sau:
{ "$schema": "https://json-schema.org/schema", "$id": "YourGeneratorName", "title": "Your Generator Title", "description": "Description of what your generator does", "type": "object", "properties": { // Các tùy chọn generator của bạn ở đây }, "required": ["requiredOption1", "requiredOption2"]}Ví dụ Đơn giản
Phần tiêu đề “Ví dụ Đơn giản”Đây là một ví dụ đơn giản với một số tùy chọn cơ bản:
{ "$schema": "https://json-schema.org/schema", "$id": "ComponentGenerator", "title": "Create a Component", "description": "Creates a new React component", "type": "object", "properties": { "name": { "type": "string", "description": "Component name", "x-priority": "important" }, "directory": { "type": "string", "description": "Directory where the component will be created", "default": "src/components" }, "withTests": { "type": "boolean", "description": "Whether to generate test files", "default": true } }, "required": ["name"]}Lời nhắc Tương tác (CLI)
Phần tiêu đề “Lời nhắc Tương tác (CLI)”Bạn có thể tùy chỉnh các lời nhắc hiển thị khi chạy generator thông qua CLI bằng cách thêm thuộc tính x-prompt:
"name": { "type": "string", "description": "Component name", "x-prompt": "What is the name of your component?"}Đối với các tùy chọn boolean, bạn có thể sử dụng lời nhắc yes/no:
"withTests": { "type": "boolean", "description": "Whether to generate test files", "x-prompt": "Would you like to generate test files?"}Lựa chọn Dropdown
Phần tiêu đề “Lựa chọn Dropdown”Đối với các tùy chọn có một tập hợp các lựa chọn cố định, sử dụng enum để người dùng có thể chọn từ một trong các tùy chọn.
"style": { "type": "string", "description": "The styling approach to use", "enum": ["css", "scss", "styled-components", "none"], "default": "css"}Dropdown Chọn Project
Phần tiêu đề “Dropdown Chọn Project”Một mẫu phổ biến là cho phép người dùng chọn từ các dự án hiện có trong workspace:
"project": { "type": "string", "description": "The project to add the component to", "x-prompt": "Which project would you like to add the component to?", "x-dropdown": "projects"}Thuộc tính x-dropdown: "projects" cho Nx biết để điền vào dropdown với tất cả các dự án trong workspace.
Đối số Vị trí
Phần tiêu đề “Đối số Vị trí”Bạn có thể cấu hình các tùy chọn để được truyền dưới dạng đối số vị trí khi chạy generator từ dòng lệnh:
"name": { "type": "string", "description": "Component name", "x-priority": "important", "$default": { "$source": "argv", "index": 0 }}Điều này cho phép người dùng chạy generator của bạn như nx g your-generator my-component thay vì nx g your-generator --name=my-component.
Thiết lập Mức độ Ưu tiên
Phần tiêu đề “Thiết lập Mức độ Ưu tiên”Sử dụng thuộc tính x-priority để chỉ ra các tùy chọn nào quan trọng nhất:
"name": { "type": "string", "description": "Component name", "x-priority": "important"}Các tùy chọn có thể có mức độ ưu tiên là "important" hoặc "internal". Điều này giúp Nx sắp xếp các thuộc tính trong tiện ích mở rộng Nx VSCode và Nx CLI.
Giá trị Mặc định
Phần tiêu đề “Giá trị Mặc định”Bạn có thể cung cấp giá trị mặc định cho các tùy chọn:
"directory": { "type": "string", "description": "Directory where the component will be created", "default": "src/components"}Thông tin Thêm
Phần tiêu đề “Thông tin Thêm”Để biết thêm chi tiết về schemas, tham khảo tài liệu Nx Generator Options.
Kiểu TypeScript với schema.d.ts
Phần tiêu đề “Kiểu TypeScript với schema.d.ts”Cùng với schema.json, generator tạo một tệp schema.d.ts cung cấp các kiểu TypeScript cho các tùy chọn generator của bạn:
export interface YourGeneratorSchema { name: string; directory?: string; withTests?: boolean;}Interface này được sử dụng trong triển khai generator của bạn để cung cấp type safety và code completion:
import { YourGeneratorSchema } from './schema';
export default async function (tree: Tree, options: YourGeneratorSchema) { // TypeScript biết các kiểu của tất cả các tùy chọn của bạn const { name, directory = 'src/components', withTests = true } = options; // ...}Triển khai một Generator
Phần tiêu đề “Triển khai một Generator”Sau khi tạo generator mới như trên, bạn có thể viết triển khai của mình trong generator.ts.
Một generator là một hàm biến đổi một hệ thống tệp ảo (Tree), đọc và ghi các tệp để thực hiện các thay đổi mong muốn. Các thay đổi từ Tree chỉ được ghi vào đĩa khi generator kết thúc thực thi, trừ khi nó được chạy ở chế độ “dry-run”. Một generator trống trông như sau:
export const myGenerator = async (tree: Tree, options: MyGeneratorSchema) => { // Sử dụng tree để áp dụng các thay đổi};
export default myGenerator;Dưới đây là một số thao tác phổ biến bạn có thể muốn thực hiện trong generator của mình:
Đọc và Ghi Tệp
Phần tiêu đề “Đọc và Ghi Tệp”// Đọc một tệpconst content = tree.read('path/to/file.ts', 'utf-8');
// Ghi một tệptree.write('path/to/new-file.ts', 'export const hello = "world";');
// Kiểm tra xem tệp có tồn tại khôngif (tree.exists('path/to/file.ts')) { // Làm gì đó}Tạo Tệp từ Templates
Phần tiêu đề “Tạo Tệp từ Templates”Bạn có thể tạo các tệp bằng tiện ích generateFiles từ @nx/devkit. Điều này cho phép bạn định nghĩa các template theo cú pháp EJS, và thay thế các biến.
import { generateFiles, joinPathFragments } from '@nx/devkit';
// Tạo các tệp từ templatesgenerateFiles( tree, joinPathFragments(__dirname, 'files'), // Thư mục template 'path/to/output', // Thư mục đầu ra { // Các biến để thay thế trong templates name: options.name, nameCamelCase: camelCase(options.name), nameKebabCase: kebabCase(options.name), // Thêm các biến khác nếu cần },);Biến đổi Code với GritQL
Phần tiêu đề “Biến đổi Code với GritQL”Bạn có thể sử dụng GritQL để tìm kiếm và biến đổi mã nguồn một cách khai báo trong các generator của bạn. GritQL hỗ trợ nhiều ngôn ngữ bao gồm TypeScript, JavaScript, Python, HCL (Terraform), và nhiều hơn nữa — vì vậy bạn có thể sử dụng cùng một cú pháp pattern trên toàn bộ stack của mình.
Nx Plugin for AWS cung cấp hai helper:
applyGritQL(tree, filePath, pattern)— áp dụng một pattern viết lại GritQL vào một tệp và trả vềPromise<boolean>cho biết liệu có thay đổi nào được thực hiện hay khôngmatchGritQL(tree, filePath, pattern)— kiểm tra xem một pattern GritQL có khớp ở bất kỳ đâu trong tệp hay không và trả vềPromise<boolean>
import { applyGritQL, matchGritQL } from '@aws/nx-plugin/sdk/utils/ast';
// Thay thế một lời gọi hàmawait applyGritQL( tree, 'src/app.ts', '`console.log($msg)` => `logger.info($msg)`',);
// Thêm một phần tử vào mảng chỉ khi chưa cóawait applyGritQL( tree, 'src/plugins.ts', '`plugins: [$items]` => `plugins: [$items, myPlugin()]` where { $items <: not contains `myPlugin` }',);
// Kiểm tra xem một pattern có tồn tại trước khi thực hiện thay đổiif (!(await matchGritQL(tree, filePath, '`import { Auth } from "./auth"`'))) { // Thêm import}Các pattern GritQL cũng hoạt động trên các tệp không phải TypeScript. Thêm tiền tố language <name> vào pattern của bạn để nhắm đến các ngôn ngữ khác:
// Python: thay thế các câu lệnh print bằng các lời gọi loggingawait applyGritQL( tree, 'src/handler.py', 'language python\n`print($msg)` => `logger.info($msg)`',);Các pattern GritQL sử dụng các đoạn mã được phân tách bằng backtick với $metavariables làm ký tự đại diện. Sử dụng => cho việc viết lại và các mệnh đề where cho các điều kiện.
Thêm Dependencies
Phần tiêu đề “Thêm Dependencies”import { addDependenciesToPackageJson } from '@nx/devkit';
// Thêm dependencies vào package.jsonaddDependenciesToPackageJson( tree, { 'new-dependency': '^1.0.0', }, { 'new-dev-dependency': '^2.0.0', },);Định dạng Tệp Đã tạo
Phần tiêu đề “Định dạng Tệp Đã tạo”import { formatFilesInSubtree } from '@aws/nx-plugin/sdk/utils/format';
// Định dạng tất cả các tệp đã được sửa đổiawait formatFilesInSubtree(tree, 'optional/path/to/format');Đọc và Cập nhật Tệp JSON
Phần tiêu đề “Đọc và Cập nhật Tệp JSON”import { readJson, updateJson } from '@nx/devkit';
// Đọc một tệp JSONconst packageJson = readJson(tree, 'package.json');
// Cập nhật một tệp JSONupdateJson(tree, 'tsconfig.json', (json) => { json.compilerOptions = { ...json.compilerOptions, strict: true, }; return json;});Mở rộng một Generator từ Nx Plugin for AWS
Phần tiêu đề “Mở rộng một Generator từ Nx Plugin for AWS”Bạn có thể import các generator từ Nx Plugin for AWS, và mở rộng hoặc kết hợp chúng theo ý muốn, ví dụ bạn có thể muốn tạo một generator xây dựng dựa trên một dự án TypeScript:
import { tsProjectGenerator } from '@aws/nx-plugin/sdk/ts';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { const callback = await tsProjectGenerator(tree, { ... });
// Mở rộng generator dự án TypeScript ở đây
// Trả về callback để đảm bảo dependencies được cài đặt. // Bạn có thể wrap callback nếu muốn thực hiện các thao tác bổ sung trong generator callback. return callback;};Generators OpenAPI
Phần tiêu đề “Generators OpenAPI”Bạn có thể sử dụng và mở rộng các generator mà chúng tôi sử dụng cho TypeScript clients và hooks theo cách tương tự như trên:
import { openApiTsClientGenerator } from '@aws/nx-plugin/sdk/open-api';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { await openApiTsClientGenerator(tree, { ... });
// Thêm các tệp bổ sung ở đây};Chúng tôi cũng cung cấp một phương thức cho phép bạn xây dựng một cấu trúc dữ liệu có thể được sử dụng để lặp qua các operations trong một đặc tả OpenAPI và do đó điều khiển việc tạo mã của riêng bạn, ví dụ:
import { buildOpenApiCodeGenerationData } from '@aws/nx-plugin/sdk/open-api.js';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { const data = await buildOpenApiCodeGenerationData(tree, 'path/to/spec.json');
generateFiles( tree, joinPathFragments(__dirname, 'files'), // Thư mục template 'path/to/output', // Thư mục đầu ra data, );};Điều này cho phép bạn viết các template như:
export const myOperationNames = [<%_ allOperations.forEach((op) => { _%> '<%- op.name %>',<%_ }); _%>];Tham khảo codebase trên GitHub để biết các ví dụ template phức tạp hơn.
Chạy Generator của Bạn
Phần tiêu đề “Chạy Generator của Bạn”Bạn có thể chạy generator của mình theo hai cách:
- Cài đặt Nx Console VSCode Plugin nếu bạn chưa cài đặt
- Mở Nx Console trong VSCode
- Nhấp
Generate (UI)trong phần "Common Nx Commands" - Tìm kiếm
@my-project/nx-plugin - my-generator - Điền các tham số bắt buộc
- Nhấp
Generate
pnpm nx g @my-project/nx-plugin:my-generatoryarn nx g @my-project/nx-plugin:my-generatornpx nx g @my-project/nx-plugin:my-generatorbunx nx g @my-project/nx-plugin:my-generatorBạn cũng có thể thực hiện chạy thử để xem những tệp nào sẽ bị thay đổi
pnpm nx g @my-project/nx-plugin:my-generator --dry-runyarn nx g @my-project/nx-plugin:my-generator --dry-runnpx nx g @my-project/nx-plugin:my-generator --dry-runbunx nx g @my-project/nx-plugin:my-generator --dry-runKiểm tra Generator của Bạn
Phần tiêu đề “Kiểm tra Generator của Bạn”Các bài kiểm tra đơn vị cho generators rất đơn giản để triển khai. Đây là một mẫu điển hình:
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';import { yourGenerator } from './generator';
describe('your generator', () => { let tree;
beforeEach(() => { // Tạo một workspace tree trống tree = createTreeWithEmptyWorkspace();
// Thêm bất kỳ tệp nào đã tồn tại trong tree tree.write( 'project.json', JSON.stringify({ name: 'test-project', sourceRoot: 'src', }), );
tree.write('src/existing-file.ts', 'export const existing = true;'); });
it('should generate expected files', async () => { // Chạy generator await yourGenerator(tree, { name: 'test', // Thêm các tùy chọn bắt buộc khác });
// Kiểm tra rằng các tệp đã được tạo expect(tree.exists('src/test/file.ts')).toBeTruthy();
// Kiểm tra nội dung tệp const content = tree.read('src/test/file.ts', 'utf-8'); expect(content).toContain('export const test');
// Bạn cũng có thể sử dụng snapshots expect(tree.read('src/test/file.ts', 'utf-8')).toMatchSnapshot(); });
it('should update existing files', async () => { // Chạy generator await yourGenerator(tree, { name: 'test', // Thêm các tùy chọn bắt buộc khác });
// Kiểm tra rằng các tệp hiện có đã được cập nhật const content = tree.read('src/existing-file.ts', 'utf-8'); expect(content).toContain('import { test } from'); });
it('should handle errors', async () => { // Mong đợi generator ném ra lỗi trong các điều kiện nhất định await expect( yourGenerator(tree, { name: 'invalid', // Thêm các tùy chọn sẽ gây ra lỗi }), ).rejects.toThrow('Expected error message'); });});Các điểm chính để kiểm tra generators:
- Sử dụng
createTreeWithEmptyWorkspace()để tạo một hệ thống tệp ảo - Thiết lập bất kỳ tệp tiên quyết nào trước khi chạy generator
- Kiểm tra cả việc tạo các tệp mới và cập nhật các tệp hiện có
- Sử dụng snapshots cho nội dung tệp phức tạp
- Kiểm tra các điều kiện lỗi để đảm bảo generator của bạn thất bại một cách nhẹ nhàng
Đóng góp Generators cho @aws/nx-plugin
Phần tiêu đề “Đóng góp Generators cho @aws/nx-plugin”Bạn cũng có thể sử dụng ts#nx-generator để tạo scaffold cho một generator trong @aws/nx-plugin.
Khi generator này được chạy trong repository của chúng tôi, nó sẽ tạo các tệp sau cho bạn:
Thư mụcpackages/nx-plugin/src/<name>/
- schema.json Schema cho đầu vào của generator
- schema.d.ts Các kiểu TypeScript cho schema
- generator.ts Triển khai generator
- generator.spec.ts Các bài kiểm tra cho generator
Thư mụcdocs/src/content/docs/guides/
- <name>.mdx Trang tài liệu cho generator
- packages/nx-plugin/generators.json Được cập nhật để bao gồm generator của bạn
Sau đó bạn có thể bắt đầu triển khai generator của mình.