albatrosary's blog

UI/UXとエンタープライズシステム

YEOMAN Advent Calendar 22日目:generator-generator を紹介します

ジェネレータ generator-generator を紹介します。このエントリーは「YEOMAN Advent Calendar 2014」12月22日の記事です。

YEOMAN Advent Calendar 2014 - Adventar

generator-generator とは

generator-generator とは generator を作るためのジェネレータです。既存のジェネレータを参考に拡張していく方法もありますが、一から自分で作る場合このジェネレータを使うと良い(かもしれない)です。いつもと同じようにインストールしていきます。

$ npm install -g generator-generator

今回は何かしらのジェネレータを作りますので generator-work というディレクトリを作りそこでジェネレータを作ります。

$ mkdir generator-work && cd $_
$ yo generator

yoコマンドでジェネレータに関することを聞かれます

  • githubアカウント
  • ジェネレータ名(今回はhelloworld)

そうして作られたファイルが

f:id:albatrosary:20141222184115p:plain

yo コマンドで作ったジェネレータを実行するための準備

作成したジェネレータを実行するためにnpmが認識できるパスにファイルを置く必要があります。ただしファイルを移動したりするとめんどうなのでリンクで代用します。自分の場合はnodebrewを使ってます。

$ pwd
/Users/albatrosary/.nodebrew/current/lib/node_modules
$ ln -s /Users/albatrosary/Project/generator/generator-helloworld generator-helloworld

リンクができたら実行します。

$ mkdir helloworld && cd $_
$ yo helloworld

     _-----_
    |       |    .--------------------------.
    |--(o)--|    |      Welcome to the      |
   `---------´   |     perfectHelloworld    |
    ( _´U`_ )    |        generator!        |
    /___A___\    '--------------------------'
     |  ~  |     
   __'.___.'__   
 ´   `  |° ´ Y ` 

? Would you like to enable this option? Yes
   create package.json
   create bower.json
   create .editorconfig
   create .jshintrc


I'm all done. Running bower install & npm install for you to install the required dependencies. If this fails, try running the command yourself.


npm WARN package.json package@0.0.0 No description
npm WARN package.json package@0.0.0 No repository field.
npm WARN package.json package@0.0.0 No README data
$ 

詳細

generator-generatorに関する詳細は YEOMANサイト に記載があります。

Writing Your Own Yeoman Generator | Yeoman

今回はここから一部を。app/index.js が基本的にyoコマンドで実行されるファイルです。ここに幾つかメソッドを追加して実行してみます。追加するメソッドは

  method1: function () {
    console.log('method 1 just ran');
  },
  method2: function () {
    console.log('method 2 just ran');
  },

です。これはyeoman.ioにも記載されているサンプルです。全体としては次のようになります。

'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');

module.exports = yeoman.generators.Base.extend({
  initializing: function () {
    this.pkg = require('../package.json');
  },
  method1: function () {
    console.log('method 1 just ran');
  },
  method2: function () {
    console.log('method 2 just ran');
  },
  prompting: function () {
    var done = this.async();

    // Have Yeoman greet the user.
    this.log(yosay(
      'Welcome to the perfect' + chalk.red('Helloworld') + ' generator!'
    ));

    var prompts = [{
      type: 'confirm',
      name: 'someOption',
      message: 'Would you like to enable this option?',
      default: true
    }];

    this.prompt(prompts, function (props) {
      this.someOption = props.someOption;

      done();
    }.bind(this));
  },

  writing: {
    app: function () {
      this.fs.copy(
        this.templatePath('_package.json'),
        this.destinationPath('package.json')
      );
      this.fs.copy(
        this.templatePath('_bower.json'),
        this.destinationPath('bower.json')
      );
    },

    projectfiles: function () {
      this.fs.copy(
        this.templatePath('editorconfig'),
        this.destinationPath('.editorconfig')
      );
      this.fs.copy(
        this.templatePath('jshintrc'),
        this.destinationPath('.jshintrc')
      );
    }
  },

  install: function () {
    this.installDependencies({
      skipInstall: this.options['skip-install']
    });
  }
});

これを実行するとコンソールは次のように表示されます。

$ yo helloworld

     _-----_
    |       |    .--------------------------.
    |--(o)--|    |      Welcome to the      |
   `---------´   |     perfectHelloworld    |
    ( _´U`_ )    |        generator!        |
    /___A___\    '--------------------------'
     |  ~  |     
   __'.___.'__   
 ´   `  |° ´ Y ` 

? Would you like to enable this option? Yes
method 1 just ran
method 2 just ran
   create package.json
   create bower.json
   create .editorconfig
   create .jshintrc


I'm all done. Running bower install & npm install for you to install the required dependencies. If this fails, try running the command yourself.


npm WARN package.json package@0.0.0 No description
npm WARN package.json package@0.0.0 No repository field.
npm WARN package.json package@0.0.0 No README data
$ 

次にアプリケーションで使う index.html を付け加えます。templates ディレクトリの中に indexhtmlファイルを登録します。ファイルの内容は

<html>
  <head>
    <title><%= title %></title>
  </head>
</html>

index.js の writing に次のロジックを追加します

      this.fs.copyTpl(
        this.templatePath('index.html'),
        this.destinationPath('app/index.html'),
        { title: 'Templating with Yeoman' }
      );

そうすると全体では

'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');

module.exports = yeoman.generators.Base.extend({
  initializing: function () {
    this.pkg = require('../package.json');
  },
  method1: function () {
    console.log('method 1 just ran');
  },
  method2: function () {
    console.log('method 2 just ran');
  },
  prompting: function () {
    var done = this.async();

    // Have Yeoman greet the user.
    this.log(yosay(
      'Welcome to the perfect' + chalk.red('Helloworld') + ' generator!'
    ));

    var prompts = [{
      type: 'confirm',
      name: 'someOption',
      message: 'Would you like to enable this option?',
      default: true
    }];

    this.prompt(prompts, function (props) {
      this.someOption = props.someOption;

      done();
    }.bind(this));
  },

  writing: {
    app: function () {
      this.fs.copy(
        this.templatePath('_package.json'),
        this.destinationPath('package.json')
      );
      this.fs.copy(
        this.templatePath('_bower.json'),
        this.destinationPath('bower.json')
      );
      this.fs.copyTpl(
        this.templatePath('index.html'),
        this.destinationPath('app/index.html'),
        { title: 'Templating with Yeoman' }
      );
    },

    projectfiles: function () {
      this.fs.copy(
        this.templatePath('editorconfig'),
        this.destinationPath('.editorconfig')
      );
      this.fs.copy(
        this.templatePath('jshintrc'),
        this.destinationPath('.jshintrc')
      );
    }
  },

  install: function () {
    this.installDependencies({
      skipInstall: this.options['skip-install']
    });
  }
});

これを実行すると appディレクトリ内にindex.htmlファイルが作成されます。できたhtmlは

<html>
  <head>
    <title>Templating with Yeoman</title>
  </head>
</html>

最後に

generator-generatorを使ってオリジナルジェネレータを作るのも良いかと思います(既存のジェネレータをカスタマイズするのも良いかと)。残りのアドベントカレンダーではこのgenerator-generatorについて記載していきたいと考えております。