Edited at

yeoman-generatorを長持ちさせるhowto、いまさら

More than 1 year has passed since last update.


TL;DR

yeoman-generatorはつらい。よいalternative generatorあったら教えてください!! giter8かな。golangだとなおいい。

そんなyeoman-generatorを長持ちさせるhowto。


yeomanオワコン説

だいたい yeoman-generator はオワコンだし近づきたくないものとして扱われる(要出典)。alternativeとしてslashplopというのが一瞬人気が出たが、オワコンのyeomanより先にしんでいった…


メンテナンス性

yeoman自体は生きているが、だいたいのyeoman-generatorはしんでいる。

Discovering Generators

あたりまえだが大体のgeneratorは作って動いたところで飽きる。そしてそんなに頻繁には使わない。

使いたい人が自分好みにしたいな、と思った時に、オプションをつける。が、自分好みにしたい人は、自分好みにしたところで飽きるので、継続してメンテするわけではない。

まだ単純な例だけど、generator-webappこんな感じになる。

{

"eslintConfig": {
"env": {<% if (includeBabel) { %>
"es6": true,<% } %>
"node": true,
"browser": true<% if (includeJQuery) { %>,
"jquery": true<% } %>
}
}
}

結果if-elseまみれのよくわからないフォーマットのよくわからないファイルができる。つらい。


暗黙のルールが負担

templateにpackage.jsonがそのままの名前で置けない。_package.jsonでおいているgeneratorが多いかな。あと、ドットで始まるファイルをコピーしない、など。_gitignore のようにunderscore prefixにして、運ぶときにリネームしているgeneratorが多い。


作っている時に動かしたあとの挙動がわかりにくい

linkとかunlinkとかよくわからない。


一年ぶりに直そうと思った時にイミフでもう直せない

こんなだった。

var yeoman = require('yeoman-generator');

module.exports = yeoman.Base.extend({
init: function () {

???

const Generator = require('yeoman-generator');

module.exports = class extends Generator {}


長持ちさせるhowto

上記の逆をやる。


if-elseで分岐しない

あきらめる。opinionatedでいこう。


用途ごとに分ける

よくあるcommand lineありなしみたいなもの。2個も3個もif elseが出てきたら、それはもう別物なので、仕組みを分ける。Sindreさんがそうしているからもう正しい。node-module-boilerplate内のboilerplateとcli-boilerplate。

(だけどgenerator-nm側では1個にしてるんだよね、こっちはよくわからない)


小さく作る

小さく作って選択肢を減らそう。


よく使う

よく使え。


暗黙のルールはスクリプトにする

最終構成の形で、ファイルを配置する。ルールはファイルを置くときには考えなくていい。コピーするスクリプトでテンプレートにする。

const rimraf = require('rimraf');

const pify = require('pify');
const path = require('path');
const copy = require('copy-concurrently');
const uniqueString = require('unique-string');
const tempDir = require('temp-dir');
const move = require('move-concurrently');
const globby = require('globby');

const getPath = () => path.join(tempDir, uniqueString());
const buildTemplate = (tempDest, copyDest, sourceDir) => {
return Promise.resolve().then(() => {
return copy(sourceDir, tempDest);
}).then(() => {
console.log(`copied to ${tempDest}`);
return pify(rimraf)(copyDest);
}).then(() => {
console.log(`removed ${copyDest}`);
return move(path.join(tempDest, 'package.json'), path.join(tempDest, '_package.json'));
}).then(() => {
return globby(['.*'], { cwd: tempDest });
}).then((value) => {
console.log(value);
return Promise.all(value.map((dotFile) => {
return move(path.join(tempDest, dotFile), path.join(tempDest, dotFile.replace(/^./, '__')));
}));
}).then(() => {
return copy(tempDest, copyDest);
}).then(() => {
console.log('completed');
});
};

Promise.resolve().then(() => {
const tempDest = getPath();
console.log(tempDest);
const copyDest = path.join('generator-rustm', 'generators', 'app', 'templates');
return buildTemplate(tempDest, copyDest, 'boilerplate');
}).then(() => {
const tempDest = getPath();
console.log(tempDest);
const copyDest = path.join('generator-rustmc', 'generators', 'app', 'templates');
return buildTemplate(tempDest, copyDest, 'cli-boilerplate');
}).catch(err => {
console.error(err);
});

update.js


run-yo で簡単に実行する

example ディレクトリに出力するようにしておけば便利。

$ run-yo --help

Usage
run-yo [input (default: example)]

Examples
run-yo
(run the yeoman generator from ./ to ./example/ )


継続アップデート

tachikomagreenkeeperをどうぞ。


完成したもの

https://github.com/pandawing/rust-module-boilerplate/

こちらです。

参照: scaffold tools | 實松アウトプット