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
系が出てくるだろうから、このメッセージを見れる日は近い。