Yeoman入門(第二部、generatorを作る)を参考にyoeman generatorを作成していたが、yeomanが更新されて現在は少し作り方が変わっているようなので新しい作成方法をメモ。
generator-generatorのインストール
generatorの雛形を生成するgenerator-generator
をインストール。
npm install generator-generator -g
helloworld generatorを作成するためのディレクトリを用意して移動。
mkdir generator-helloworld
cd generator-helloworld
generator-helloworldの雛形作成
generatorの雛形を生成
yo generator
コマンドを実行すると、gitのユーザ名を聞かれた後、generatorの名前を聞かれるのでhelloworldと入力してenter。
(そのままenterを押すとgeneratorの名前がgenerator-generator-helloworldになります。)
[?] What's the base name of your generator? (generator helloworld) helloworld
コマンドの実行が終了すると、以下のようなフォルダ構成になっているかと思います。
.
├── README.md
├── node_modules
├── generators
│ └── app
│ ├── index.js
│ └── templates
│ ├── _bower.json
│ ├── _package.json
│ ├── editorconfig
│ └── jshintrc
├── package.json
└── test
└── test-app.js
generator-helloworldの動作確認
ここで一旦generator-helloworldの動作確認をします。
適当なディレクトリを作って、移動。
mkdir test-helloworld
cd test-helloworld
さらに、node_modulesディレクトリを作って、node_modulesディレクトリ以下にシンボリックリンクでgenerator-helloworldを配置します。
mkdir node_modules
cd node_modules
ln -s <generator-helloworldへのパス> .
.
├── README.md
├── node_modules
│ └── generator-helloworld
Yeomanは、node_modulesに配置されている'generator-'で始まるパッケージをgeneratorと認識するので、これによってgenerator-helloworldがgeneratorと認識されるようになります。
次に、yo helloworld
でgenerator-helloworldを実行。
この際、以下のエラーがでる場合は、generators/app/index.jsのrequire('../package.json')
をrequire('../../package.json')
に直して下さい。
(YeomanでError: Cannot find module '../package.json'が表示される問題の対策)
events.js:72
throw er; // Unhandled 'error' event
^
Error: Cannot find module '../package.json'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at module.exports.yeoman.generators.Base.extend.initializing (/Users/ryo/Programming/web/generator-helloworld/generators/app/index.js:8:16)
at /Users/ryo/Programming/web/generator-helloworld/node_modules/yeoman-generator/lib/base.js:421:16
at processImmediate [as _immediateCallback] (timers.js:336:15)
コマンドの実行が終了すると、以下のような構成のファイルが生成されているかと思います。
.
├── .editorconfig
├── .jshintrc
├── bower.json
├── node_modules
│ └── generator-helloworld
└── package.json
generator-helloworldの編集
generatorの中核となる処理は、generators/app/index.js
に書かれているので、このファイルを開いてみます。
'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');
},
prompting: function () {
var done = this.async();
// Have Yeoman greet the user.
this.log(yosay(
'Welcome to the super-excellent ' + 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.props = props;
// To access props later use this.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();
}
});
ここに、ユーザ名を尋ねるpromptを表示する処理を追加します。
…
var prompts = [{
type: 'confirm',
name: 'someOption',
message: 'Would you like to enable this option?',
default: true
},
{
name: 'yourname',
message: 'What is your name?',
default: "someuser"
}];
…
次に、index.htmlをgenerators/app/templatesに配置します。
<html>
<body>
<h1>Hello, <%= yourname %></h1>
</body>
</html>
上記の<%= yourname %>
の部分にpromptで入力されたユーザ名を埋め込む処理をgenerators/app/index.jsに記述します。
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')
);
// generators/app/templates/index.htmlを対象のディレクトリにコピーして、
// yournameにユーザ名を埋め込む
this.fs.copyTpl(
this.templatePath('index.html'),
this.destinationPath('index.html'),
{yourname: this.props.yourname}
);
},
promptで入力された値は、this.props
経由でアクセスできます。
generator-helloworldの再実行
test-helloworldを一旦削除し、初期と同じ以下の構成に戻します。
.
├── README.md
├── node_modules
│ └── generator-helloworld
rm -rf test-helloworld
mkdir test-helloworld
cd test-helloworld
mkdir node_modules
cd node_modules
ln -s <generator-helloworldのパス> .
最後に、test-helloworld内に移動して、yo helloworld
を実行し、promptで入力した名前が表示されていれば成功です。
cd test-helloworld
yo helloworld
open index.html