
gulpのGetting Startedにもあるように、gulpを使うにはグローバルインストールとローカルインストールが必要になる。なんで同じものを2つインストールするのか、不思議に思ってソース読んで「へー」と思ったのでまとめてみる。
Gruntの場合
Gruntの場合はgrunt-cliをグローバルにインストールしてgruntはローカルにインストールする。grunt-cliはローカルにインストールしたgruntを呼び出すためだけのモジュールだ。タスクを走らすgruntと、そのgruntを実行するgrunt-cli、2つのモジュールは明確に役割が切り離されている。
Gruntがこうなってる理由は、異なるプロジェクトで使ってるgruntのバージョンが違うと、グローバルにインストールされてるgruntのバージョン次第で、そのタスク(Gruntfile)が動かせない可能性が出てくるから。
(参考: Grunt v0.4.0 での変更点 | Takazudolog)
gulpの場合
gulpもGruntと同じで、グローバルにインストールされたgulpはローカルにインストールされたgulpを実行するためにインストールする。でもこのグローバルとローカルの2つのモジュールの中身は完全に同じもので、まったく同じモジュールをグローバルとローカルにインストールすることになる。ここにGruntとのアプローチの違いがある
gulpのアプローチ
gulpのソースを見ると次のようなコードがある。
|
|
envには実行しているディテクトリのパスやgulpfileのパスなどが入っている。env.modulePathにはローカルのnode_modulesにあるgulpのパスが入っている。gulpコマンドが実行されると、このrequireでローカルのgulpをインポートして、実際の処理(gulpfileに書かれたタスク)はrequireされたローカルのgulpモジュールが全て行う。自分自身が自分自身と同じモジュールをrequireして使うという仕組みだ(厳密には同じじゃないけどまぁ同じということで)。おもしろい!
ローカルにgulpがインストールされてない場合
ローカルにgulpがインストールされてない場合には次のようなチェックではじいている。
|
|
ローカルにgulpがインストールされてない場合はenv.modulePathはundefinedになる。ここではじくことで処理が終わる。
まとめ
Gruntはgunrt-cliとgruntを別のモジュールにして役割を分けた。
gulpは同じgulpの中で別のgulpをモジュールとしてrequireするというアプローチを取っている。グローバルとローカル、同じモジュールに2つの役割を持たせて、プロジェクトごとのgulpのバージョンの違いを吸収している。個人的にはgulpのアプローチのほうがカッコイイと思う。スマートだ。
今回gulpのソースを読んでみて、gulpというかNode.jsがおもしろいと思った。
おまけ
gulpは最近何かと話題のsemverのチェックもしている。
|
|
グローバルとローカルのバージョンがsemver的に合ってない場合は警告を出してくる。もうすぐ4.x系が出てくるだろうから、このメッセージを見れる日は近い。