gulp vs Grunt
概要
gulpの入門記事を以下に書いて行きます。
- 目次
- gulpとは
- gulp sample
- gulp支える技術(Streamと並行性)
- grunt vs gulp どっち使う?
gulp.jsとは
- いわゆるフロントエンド周りの
- task runner
- build tool
Gruntあるでしょ
- その通り
- いわば、Gruntの簡易版
- 去年位?出来た後発のtool
- 最近、blog記事も増えてきた
公式Page売り文句
- 複雑なtaskも管理し易く、simpleで、使うのが簡単
- 一時fileのdisk書き込みが無いので早くて能率的
- simpleで期待通り動くようにPluginのGuidelineがある
- APIが小さく学習時間かからない
リソース
- gulp公式page
- 入門記事
sample多め
全体像
使い方の流れ
- Gruntと一緒
- pluginを追加
npm install gulp-xxx --save-dev
- gulpfileの更新
gulp.task('task-name', function(){ /* settings */ });
gulpfileとは
- 設定file(Gruntfileと一緒)
// 公式pageより // requireは省略。 gulp.task('scripts', function() { return gulp.src(paths.scripts) .pipe(coffee()) .pipe(uglify()) .pipe(concat('all.min.js')) .pipe(gulp.dest('build/js')); }); gulp.task('watch', function() { gulp.watch(paths.scripts, ['scripts']); }); gulp.task('default', ['scripts', 'watch']);
install
npm install -g gulp
$ gulp -v [gulp] CLI version 3.6.2
やってみる
- 今から、jsファイルをミニファイする簡単なgulp project作ってみる
project作成
- まずは、地盤固めから
mkdir my_first_gulp cd my_first_gulp npm init npm install --save-dev gulp
plugin追加
- minifyするplugin
npm install gulp-uglify --save-dev
設定ファイル
- gulpfile.jsを作成
var gulp = require('gulp'); var uglify = require('gulp-uglify'); gulp.task("uglify", function() { return gulp.src('js/*js') .pipe(uglify()) .pipe(gulp.dest("build/js")); }); gulp.task("watch", function() { return gulp.watch('js/*js', ['uglify']); }); gulp.task('default', ['uglify', 'watch']);
実験
- 試しにBackbone突っ込む
mkdir js cd js curl -O http://backbonejs.org/backbone.js cd ..
run
- 実行
- build/js/backbone.jsがminifyした?
gulp
振り返ってみる
- 今作ったsampleを一つずつ振り返ってみる
- 関連する技術をピックアップしながら進める
- streamや並列性の話
library呼び出し
var gulp = require('gulp'); var uglify = require('gulp-uglify');
- gulp本体とplugin呼び出してる
task
gulp.task("uglify", function() { return // ...any action });
- これで、taskを定義している
- この後、以下を黒い画面で実行できる
gulp uglify
taskの中身
return gulp.src('js/*js') .pipe(uglify()) .pipe(gulp.dest("build/js"));
- src => pipe => destという流れ
- gulp = node.jsのstreamを使ってる(後述)
- pipeの中で、uglify()等、先ほど呼び出した関数を実行
streamとは
- stream
- データの流れを抽象化したもの
- unixの pipeでやりとりしてる物と同じ
例示
- ※stream handbookより
- 今から以下の2つを比較して、何故stream要るか見てみる
- text読んで渡す処理を
- 通常とstream使用で比較してみる
通常で書くと
var http = require('http'); var fs = require('fs'); var server = http.createServer(function (req, res) { fs.readFile(__dirname + '/data.txt', function (err, data) { res.end(data); }); }); server.listen(8000);
- 問題点
- 扱いづらい
- memoryにfile内容をbufferしてる
- もし、data.txt馬鹿でかいと、多くのUserがメモリを食い散らかす
Stream使うと
var http = require('http'); var fs = require('fs'); var server = http.createServer(function (req, res) { var stream = fs.createReadStream(__dirname + '/data.txt'); stream.pipe(res); }); server.listen(8000);
- happy
- 奇麗
- diskからdata受け取るときに、data破片毎にclientに書き込める
- さっきの、でかいバッファ分の利用がなくなった
- このstreamの運搬してるのがpipe
- ここまでstream handbookでしたー
gulpのpipe
return gulp.src('js/*js') .pipe(uglify()) .pipe(gulp.dest("build/js"));
- gulp.src : file のstreamを作ってる
- pipe : streamを流す
- dest : streamを保存
gulp.srcについて
- 第2引数がoptions objでbuffer有無を設定出来る
- falseにすると、streamとしてfile.contentsを渡せるが
- 実はデフォルトはtrue
- File bufferも一応残してる
- pluginがstream対応していない事があるので、そうしてるらしい
sample
gulp.task('default', ['uglify', 'watch']);
- default taskを指定
- これで、黒い画面で
gulp
だけで打つと、uglifyとwatchタスクを実行する - ※ちなみに、以前あったgulp.runは今使えないっぽいので注意
- これで、黒い画面で
並列化について
gulp.task('default', ['uglify', 'watch']);
- 基本的に、自動的に並列化(並行化※後述)される
- 例だと、uglifyとwatchは順序は保証されない
並列化の仕組み
- js = single thread
- あれ?並列化?
- どうやってるんだろう?
言葉の整理から
- 1task以上を同時に実行する言葉は2つある
- parrallel(並列)
- concurrent(並行)
- 違いは、後者の並行が、
- 本当に並列である場合もあれば、
- 場合によっては時間毎に切り替える等の仮想的な並列である場合もある
- 参考
gulpは?
- gulpは、concurrency(並行)
- orchestratorを使ってるらしい
- orchestratorは、出来る範囲の並行性の中でタスクや依存性の順序並べや実行をしていくmodule
Orchestratorのconcurrency
- ソースを追うと、どうやら、
- 単に全task実行して
- それぞれ終了時のcallbackを指定していってるだけっぽい
- IO部分は確かに並列だが、それ以外はいつも通り
- (実際は、後述の直列の要素もあるのでもう少し複雑だが)
- "In node, everything runs in parallel, except your code" っていうヤツでしょうか。
gulpのTask実行順を指定
- gulpの話に戻ると
- taskを並列(並行)でなく直列にするには、以下、2つの条件が必要
- 1)依存してるtaskは非同期
- 2)taskの依存関係を指定
1)依存してるtaskは非同期
- 以下、いずれかの方法
- streamを返す事(src->pipe->destまでは非同期で直列)
- callbackを呼び出す事(mochaのdoneと同じ)
- promiseを返す事
2)taskの依存関係を指定
- 以下のdepsに、依存してるタスク名を書く
- taskの関数
gulp.task(name[, deps], fn)
- name : taskの名前
- deps:依存関係のあるタスク
- fn:その後実行する関数
gulp.task('default', ['uglify', 'watch'], function(){ // uglifyとwatch終わった後に実行される });
複雑な順番
gulp.task('a'); gulp.task('b', ['a']); gulp.task('c', ['a']); gulp.task('d', ['b', 'c']);
- この場合、いずれか
- a -> b -> c -> d
- a -> c -> b -> d
- orchestratorの中のsequencifyというlibが巧い事やってくれるらしい
- 参考
以上
- 大体ここまでの内容分かれば使えるはず
- 以下から好きなプラグイン探して入れて設定して使って行けばよい
gulp vs Grunt
- これも、どっちが生き残るのかな?
pluginの数は?
- Gruntが勿論、多い
- 2899個
- gulpは比較すると少ないが、数は増えてる
- 706個
- 普通に使う分には困らなさそう
- 数値はいずれも、公式ページから(2014/5/25現在)
Gruntのこれから
- 視点を変えてGruntの方を見てみる
- ver0.5で、並列実行が付く?(Roldmap)
grunt.registerTask('name', ['jshint', 'concat'], { parallel:true });
- ver1.0で、先程出てきたOrchestrator対応する?(grunt 1.0 alfa)
Gruntさん
- 大分gulpを意識してる?
- 並列性(並行性?)が入ってきそう
- 書き方も変わりそう
Gruntでgulp like
- gulp本家がsrcからdestまでのstream使う仕組みを外出し
- これでGruntでもgulp likeに書ける