ジェネレーターの実行時コンテキスト

ジェネレーターを作成する際に理解すべき最も重要な概念の 1 つは、メソッドがどのように実行され、どのコンテキストで実行されるかです。

アクションとしてのプロトタイプメソッド

ジェネレーターのプロトタイプに直接アタッチされた各メソッドは、タスクとみなされます。各タスクは、Yeoman 環境の実行ループによって順次実行されます。

言い換えれば、Object.getPrototypeOf(Generator) によって返されるオブジェクト上の各関数は、自動的に実行されます。

ヘルパーメソッドとプライベートメソッド

プロトタイプメソッドがタスクとみなされることがわかったので、自動的に呼び出されないヘルパーメソッドやプライベートメソッドをどのように定義するのか疑問に思うかもしれません。これを実現するには、3 つの異なる方法があります。

  1. メソッド名の先頭にアンダースコアを付ける (例: _private_method)。

       class extends Generator {
         method1() {
           console.log('hey 1');
         }
    
         _private_method() {
           console.log('private hey');
         }
       }
    
  2. インスタンスメソッドを使用する

       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');
           };
         }
       }
    
  3. 親ジェネレーターを拡張する

       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 定義とうまく連携しないことに注意してください)

利用可能な優先度は (実行順に) 次のとおりです。

  1. initializing - 初期化メソッド (現在のプロジェクトの状態の確認、設定の取得など)
  2. prompting - ユーザーにオプションをプロンプトする場所 (this.prompt() を呼び出す場所)
  3. configuring - 設定を保存し、プロジェクトを構成する ( .editorconfig ファイルやその他のメタデータファイルを作成する)
  4. default - メソッド名が優先度と一致しない場合、このグループにプッシュされます。
  5. writing - ジェネレーター固有のファイル (ルート、コントローラーなど) を書き込む場所
  6. conflicts - コンフリクトが処理される場所 (内部で使用)
  7. install - インストールが実行される場所 (npm, bower)
  8. end - 最後に呼び出され、クリーンアップ、さよなら など

これらの優先度ガイドラインに従うと、ジェネレーターは他のものとうまく連携できます。

非同期タスク

タスクが非同期的に作業を完了するまで実行ループを一時停止するには、複数の方法があります。

最も簡単な方法は、Promise を返すことです。Promise が解決するとループが続行されます。または、失敗した場合は例外が発生して停止します。

依存している非同期 API が Promise をサポートしていない場合は、従来の this.async() の方法に頼ることができます。this.async() を呼び出すと、タスクが完了したら呼び出す関数が返されます。例:

asyncTask() {
  var done = this.async();

  getUserEmail(function (err, name) {
    done(err);
  });
}

done 関数がエラーパラメーター付きで呼び出された場合、実行ループは停止し、例外が発生します。

ここからどこへ進む?

yeoman の実行コンテキストについて少し理解できたので、ユーザーインタラクション を読んで先に進むことができます。