ジェネレーターを作成する際に理解すべき最も重要な概念の 1 つは、メソッドがどのように実行され、どのコンテキストで実行されるかです。
アクションとしてのプロトタイプメソッド
ジェネレーターのプロトタイプに直接アタッチされた各メソッドは、タスクとみなされます。各タスクは、Yeoman 環境の実行ループによって順次実行されます。
言い換えれば、Object.getPrototypeOf(Generator) によって返されるオブジェクト上の各関数は、自動的に実行されます。
ヘルパーメソッドとプライベートメソッド
プロトタイプメソッドがタスクとみなされることがわかったので、自動的に呼び出されないヘルパーメソッドやプライベートメソッドをどのように定義するのか疑問に思うかもしれません。これを実現するには、3 つの異なる方法があります。
- メソッド名の先頭にアンダースコアを付ける (例: - _private_method)。- class extends Generator { method1() { console.log('hey 1'); } _private_method() { console.log('private hey'); } }
- インスタンスメソッドを使用する - class extends Generator { constructor(args, opts) { // Calling the super constructor is important so our generator is correctly set up super(args, opts) this.helperMethod = function () { console.log('won\'t be called automatically'); }; } }
- 親ジェネレーターを拡張する - class MyBase extends Generator { helper() { console.log('methods on the parent generator won\'t be called automatically'); } } module.exports = class extends MyBase { exec() { this.helper(); } };
実行ループ
単一のジェネレーターの場合、タスクを順次実行することは問題ありません。しかし、ジェネレーターを一緒に構成し始めると、それだけでは十分ではありません。
そのため、Yeoman は 実行ループ を使用します。
実行ループは、優先度サポートを備えたキューシステムです。実行ループを処理するために、Grouped-queue モジュールを使用しています。
優先度は、コード内で特別なプロトタイプメソッド名として定義されます。メソッド名が優先度名と同じ場合、実行ループはメソッドをこの特別なキューにプッシュします。メソッド名が優先度と一致しない場合、default グループにプッシュされます。
コードでは、次のようになります。
class extends Generator {
  priorityName() {}
}
また、単一のメソッドの代わりにハッシュを使用することで、複数のメソッドをグループ化して、キュー内で一緒に実行することもできます。
Generator.extend({
  priorityName: {
    method() {},
    method2() {}
  }
});
(この最後のテクニックは、JS の class 定義とうまく連携しないことに注意してください)
利用可能な優先度は (実行順に) 次のとおりです。
- initializing- 初期化メソッド (現在のプロジェクトの状態の確認、設定の取得など)
- prompting- ユーザーにオプションをプロンプトする場所 (- this.prompt()を呼び出す場所)
- configuring- 設定を保存し、プロジェクトを構成する (- .editorconfigファイルやその他のメタデータファイルを作成する)
- default- メソッド名が優先度と一致しない場合、このグループにプッシュされます。
- writing- ジェネレーター固有のファイル (ルート、コントローラーなど) を書き込む場所
- conflicts- コンフリクトが処理される場所 (内部で使用)
- install- インストールが実行される場所 (npm, bower)
- end- 最後に呼び出され、クリーンアップ、さよなら など
これらの優先度ガイドラインに従うと、ジェネレーターは他のものとうまく連携できます。
非同期タスク
タスクが非同期的に作業を完了するまで実行ループを一時停止するには、複数の方法があります。
最も簡単な方法は、Promise を返すことです。Promise が解決するとループが続行されます。または、失敗した場合は例外が発生して停止します。
依存している非同期 API が Promise をサポートしていない場合は、従来の this.async() の方法に頼ることができます。this.async() を呼び出すと、タスクが完了したら呼び出す関数が返されます。例:
asyncTask() {
  var done = this.async();
  getUserEmail(function (err, name) {
    done(err);
  });
}
done 関数がエラーパラメーター付きで呼び出された場合、実行ループは停止し、例外が発生します。
ここからどこへ進む?
yeoman の実行コンテキストについて少し理解できたので、ユーザーインタラクション を読んで先に進むことができます。
