Nx Generator Generator
Nx GeneratorをTypeScriptプロジェクトに追加し、コンポーネントのスキャフォールディングや特定のプロジェクト構造の強制など、反復的なタスクの自動化を支援します。
Generatorの生成
Section titled “Generatorの生成”Generatorは2つの方法で生成できます:
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-generator変更されるファイルを確認するためにドライランを実行することもできます
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-run- インストール Nx Console VSCode Plugin まだインストールしていない場合
- VSCodeでNxコンソールを開く
- クリック
Generate (UI)"Common Nx Commands"セクションで - 検索
@aws/nx-plugin - ts#nx-generator - 必須パラメータを入力
- クリック
Generate
| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
| project 必須 | string | - | ジェネレーターを追加するTypeScriptプロジェクト。ts#nx-pluginジェネレーターを使用して作成することを推奨します。 |
| name 必須 | string | - | ジェネレーター名 |
| description | string | - | ジェネレーターの説明 |
| directory | string | - | ジェネレーターを追加するプラグインプロジェクトのソースフォルダー内のディレクトリ (デフォルト: <name>) |
| preferInstallDependencies | boolean | true | ジェネレーター実行後に依存関係のインストールを優先するかどうか。複数のジェネレーターをバッチ処理する際にインストールを延期する場合はfalseに設定します(後続のジェネレーターがNxプロジェクトグラフを計算できるよう、必要に応じてインストールは実行されます)。最後に一度だけインストールします。 |
Generatorの出力
Section titled “Generatorの出力”Generatorは、指定されたproject内に以下のプロジェクトファイルを作成します:
Directorysrc/<name>/
- schema.json Generatorへの入力のスキーマ
- schema.d.ts スキーマのTypeScript型
- generator.ts スタブGenerator実装
- generator.spec.ts Generatorのテスト
- README.md Generatorのドキュメント
- generators.json Generatorを定義するNx設定
- package.json “generators”エントリを追加するために作成または更新
- tsconfig.json CommonJSを使用するように更新
プロジェクトの変更
このGeneratorは、選択されたprojectをCommonJSを使用するように更新します。これは、Nx GeneratorがESMサポートについては現在CommonJSのみをサポートしているためです(ESMサポートについてはこのGitHub issueを参照)。
ローカルGenerators
Section titled “ローカルGenerators”ts#nx-generator Generatorを実行する際にローカルのnx-pluginプロジェクトを選択し、名前とオプションのディレクトリおよび説明を指定します。
スキーマの定義
Section titled “スキーマの定義”schema.jsonファイルは、Generatorが受け入れるオプションを定義します。これはJSON Schema形式にNx固有の拡張を加えたものに従います。
schema.jsonファイルは以下の基本構造を持ちます:
{ "$schema": "https://json-schema.org/schema", "$id": "YourGeneratorName", "title": "Your Generator Title", "description": "Description of what your generator does", "type": "object", "properties": { // Your generator options go here }, "required": ["requiredOption1", "requiredOption2"]}シンプルな例
Section titled “シンプルな例”以下は、いくつかの基本的なオプションを持つシンプルな例です:
{ "$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"]}インタラクティブプロンプト(CLI)
Section titled “インタラクティブプロンプト(CLI)”x-promptプロパティを追加することで、CLI経由でGeneratorを実行する際に表示されるプロンプトをカスタマイズできます:
"name": { "type": "string", "description": "Component name", "x-prompt": "What is the name of your component?"}ブール値オプションの場合、yes/noプロンプトを使用できます:
"withTests": { "type": "boolean", "description": "Whether to generate test files", "x-prompt": "Would you like to generate test files?"}ドロップダウン選択
Section titled “ドロップダウン選択”固定された選択肢のセットを持つオプションの場合、enumを使用して、ユーザーがオプションの1つから選択できるようにします。
"style": { "type": "string", "description": "The styling approach to use", "enum": ["css", "scss", "styled-components", "none"], "default": "css"}プロジェクト選択ドロップダウン
Section titled “プロジェクト選択ドロップダウン”一般的なパターンは、ワークスペース内の既存のプロジェクトからユーザーに選択させることです:
"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"}x-dropdown: "projects"プロパティは、Nxにワークスペース内のすべてのプロジェクトでドロップダウンを埋めるように指示します。
コマンドラインからGeneratorを実行する際に、位置引数として渡されるようにオプションを設定できます:
"name": { "type": "string", "description": "Component name", "x-priority": "important", "$default": { "$source": "argv", "index": 0 }}これにより、ユーザーはnx g your-generator --name=my-componentの代わりにnx g your-generator my-componentのようにGeneratorを実行できます。
優先度の設定
Section titled “優先度の設定”x-priorityプロパティを使用して、どのオプションが最も重要かを示します:
"name": { "type": "string", "description": "Component name", "x-priority": "important"}オプションは"important"または"internal"の優先度を持つことができます。これにより、Nx VSCode拡張機能とNx CLIでプロパティを順序付けするのに役立ちます。
デフォルト値
Section titled “デフォルト値”オプションにデフォルト値を提供できます:
"directory": { "type": "string", "description": "Directory where the component will be created", "default": "src/components"}スキーマの詳細については、Nx Generator Optionsドキュメントを参照してください。
schema.d.tsによるTypeScript型
Section titled “schema.d.tsによるTypeScript型”schema.jsonと共に、Generatorはschema.d.tsファイルを作成し、Generatorオプションに対するTypeScript型を提供します:
export interface YourGeneratorSchema { name: string; directory?: string; withTests?: boolean;}このインターフェースは、型安全性とコード補完を提供するために、Generator実装で使用されます:
import { YourGeneratorSchema } from './schema';
export default async function (tree: Tree, options: YourGeneratorSchema) { // TypeScript knows the types of all your options const { name, directory = 'src/components', withTests = true } = options; // ...}Generatorの実装
Section titled “Generatorの実装”上記のように新しいGeneratorを作成した後、generator.tsに実装を記述できます。
Generatorは仮想ファイルシステム(Tree)を変更する関数で、ファイルを読み書きして望ましい変更を行います。Treeからの変更は、Generatorの実行が完了した後にのみディスクに書き込まれます(“dry-run”モードで実行されている場合を除く)。空のGeneratorは以下のようになります:
export const myGenerator = async (tree: Tree, options: MyGeneratorSchema) => { // Use the tree to apply changes};
export default myGenerator;Generatorで実行したい一般的な操作をいくつか紹介します:
ファイルの読み書き
Section titled “ファイルの読み書き”// Read a fileconst content = tree.read('path/to/file.ts', 'utf-8');
// Write a filetree.write('path/to/new-file.ts', 'export const hello = "world";');
// Check if a file existsif (tree.exists('path/to/file.ts')) { // Do something}テンプレートからのファイル生成
Section titled “テンプレートからのファイル生成”@nx/devkitのgenerateFilesユーティリティを使用してファイルを生成できます。これにより、EJS構文でテンプレートを定義し、変数を置換できます。
import { generateFiles, joinPathFragments } from '@nx/devkit';
// Generate files from templatesgenerateFiles( tree, joinPathFragments(import.meta.dirname, 'files'), // Template directory 'path/to/output', // Output directory { // Variables to replace in templates name: options.name, nameCamelCase: camelCase(options.name), nameKebabCase: kebabCase(options.name), // Add more variables as needed },);GritQLによるコード変換
Section titled “GritQLによるコード変換”GritQLを使用して、Generator内でソースコードを宣言的に検索および変換できます。GritQLは、TypeScript、JavaScript、Python、HCL(Terraform)などの複数の言語をサポートしているため、スタック全体で同じパターン構文を使用できます。
Nx Plugin for AWSは2つのヘルパーを公開しています:
applyGritQL(tree, filePath, pattern)— GritQL書き換えパターンをファイルに適用し、変更が行われたかどうかを示すPromise<boolean>を返しますmatchGritQL(tree, filePath, pattern)— GritQLパターンがファイル内のどこかに一致するかどうかをチェックし、Promise<boolean>を返します
import { applyGritQL, matchGritQL } from '@aws/nx-plugin/sdk/utils/ast';
// Replace a function callawait applyGritQL( tree, 'src/app.ts', '`console.log($msg)` => `logger.info($msg)`',);
// Add an element to an array only if not already presentawait applyGritQL( tree, 'src/plugins.ts', '`plugins: [$items]` => `plugins: [$items, myPlugin()]` where { $items <: not contains `myPlugin` }',);
// Check if a pattern exists before making changesif (!(await matchGritQL(tree, filePath, '`import { Auth } from "./auth"`'))) { // Add the import}GritQLパターンは非TypeScriptファイルでも機能します。他の言語をターゲットにするには、パターンの前にlanguage <name>を付けます:
// Python: replace print statements with logging callsawait applyGritQL( tree, 'src/handler.py', 'language python\n`print($msg)` => `logger.info($msg)`',);GritQLパターンは、バッククォートで区切られたコードスニペットと、ワイルドカードとしての$metavariablesを使用します。書き換えには=>を、条件にはwhere句を使用します。
依存関係の追加
Section titled “依存関係の追加”import { addDependenciesToPackageJson } from '@nx/devkit';
// Add dependencies to package.jsonaddDependenciesToPackageJson( tree, { 'new-dependency': '^1.0.0', }, { 'new-dev-dependency': '^2.0.0', },);生成されたファイルのフォーマット
Section titled “生成されたファイルのフォーマット”import { formatFilesInSubtree } from '@aws/nx-plugin/sdk/utils/format';
// Format all files that were modifiedawait formatFilesInSubtree(tree, 'optional/path/to/format');JSONファイルの読み取りと更新
Section titled “JSONファイルの読み取りと更新”import { readJson, updateJson } from '@nx/devkit';
// Read a JSON fileconst packageJson = readJson(tree, 'package.json');
// Update a JSON fileupdateJson(tree, 'tsconfig.json', (json) => { json.compilerOptions = { ...json.compilerOptions, strict: true, }; return json;});Nx Plugin for AWSからGeneratorを拡張
Section titled “Nx Plugin for AWSからGeneratorを拡張”Nx Plugin for AWSからGeneratorをインポートし、必要に応じて拡張または構成できます。例えば、TypeScriptプロジェクトの上に構築されるGeneratorを作成したい場合があります:
import { tsProjectGenerator } from '@aws/nx-plugin/sdk/ts';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { const callback = await tsProjectGenerator(tree, { ... });
// Extend the TypeScript project generator here
// Return the callback to ensure dependencies are installed. // You can wrap the callback if you wish to perform additional operations in the generator callback. return callback;};OpenAPI Generators
Section titled “OpenAPI Generators”上記と同様の方法で、TypeScriptクライアントとフックに使用するGeneratorを使用および拡張できます:
import { openApiTsClientGenerator } from '@aws/nx-plugin/sdk/open-api';
export const myGenerator = async (tree: Tree, schema: MyGeneratorSchema) => { await openApiTsClientGenerator(tree, { ... });
// Add additional files here};また、OpenAPI仕様内の操作を反復処理するために使用できるデータ構造を構築できるメソッドも公開しており、独自のコード生成を実装できます。例:
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(import.meta.dirname, 'files'), // Template directory 'path/to/output', // Output directory data, );};これにより、次のようなテンプレートを記述できます:
export const myOperationNames = [<%_ allOperations.forEach((op) => { _%> '<%- op.name %>',<%_ }); _%>];より複雑なテンプレートの例については、GitHubのコードベースを参照してください。
Generatorの実行
Section titled “Generatorの実行”Generatorは2つの方法で実行できます:
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-generator変更されるファイルを確認するためにドライランを実行することもできます
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-run- インストール Nx Console VSCode Plugin まだインストールしていない場合
- VSCodeでNxコンソールを開く
- クリック
Generate (UI)"Common Nx Commands"セクションで - 検索
@my-project/nx-plugin - my-generator - 必須パラメータを入力
- クリック
Generate
Generatorのテスト
Section titled “Generatorのテスト”Generatorの単体テストは簡単に実装できます。以下は典型的なパターンです:
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';import { yourGenerator } from './generator.js';
describe('your generator', () => { let tree;
beforeEach(() => { // Create an empty workspace tree tree = createTreeWithEmptyWorkspace();
// Add any files that should already exist in the 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 () => { // Run the generator await yourGenerator(tree, { name: 'test', // Add other required options });
// Check that files were created expect(tree.exists('src/test/file.ts')).toBeTruthy();
// Check file content const content = tree.read('src/test/file.ts', 'utf-8'); expect(content).toContain('export const test');
// You can also use snapshots expect(tree.read('src/test/file.ts', 'utf-8')).toMatchSnapshot(); });
it('should update existing files', async () => { // Run the generator await yourGenerator(tree, { name: 'test', // Add other required options });
// Check that existing files were updated const content = tree.read('src/existing-file.ts', 'utf-8'); expect(content).toContain('import { test } from'); });
it('should handle errors', async () => { // Expect the generator to throw an error in certain conditions await expect( yourGenerator(tree, { name: 'invalid', // Add options that should cause an error }), ).rejects.toThrow('Expected error message'); });});Generatorをテストする際の重要なポイント:
createTreeWithEmptyWorkspace()を使用して仮想ファイルシステムを作成- Generatorを実行する前に前提条件となるファイルをセットアップ
- 新しいファイルの作成と既存のファイルの更新の両方をテスト
- 複雑なファイル内容にはスナップショットを使用
- Generatorが適切に失敗することを確認するためにエラー条件をテスト
@aws/nx-pluginへのGeneratorの貢献
Section titled “@aws/nx-pluginへのGeneratorの貢献”ts#nx-generatorを使用して、@aws/nx-plugin内にGeneratorをスキャフォールドすることもできます。
このGeneratorが私たちのリポジトリで実行されると、以下のファイルが生成されます:
Directorypackages/nx-plugin/src/<name>/
- schema.json Generatorへの入力のスキーマ
- schema.d.ts スキーマのTypeScript型
- generator.ts Generator実装
- generator.spec.ts Generatorのテスト
Directorydocs/src/content/docs/guides/
- <name>.mdx Generatorのドキュメントページ
- packages/nx-plugin/generators.json Generatorを含めるように更新
- packages/nx-plugin/sdk/<prefix>.ts SDKからGeneratorを公開するように更新(
ts#およびpy#Generatorの場合)
その後、Generatorの実装を開始できます。