はじめに
自分は長くC#のぬるま湯に使っていたおかげでWeb界隈のことがほとんどわからない。ASP.Net触ったりAzure触ったことがあるがnpm?grunt?というような感じであった。今回Gruntやnpmそしてwebpackなどを使い始めた今、要するにそれは何なのかをまとめたものが欲しかったので自分で作ることにした。
なお、今後使っていくWeb界隈とはクライアント側に限定せず、またサーバーサイドの言語も限定せずすごく広い意味でWebサービスの開発に使える技術全般のことを指すと思っていただきたい。
パッケージ管理系
パッケージ管理、あるいはライブラリの依存性解決のためのツールと言ったほうがわかりやすいだろうか。
C#を使ったことがある者であればnugetに当たる物がこれである。どうやらWeb界隈ではこのパッケージ管理をする立場にあるソフトウェアが何種類かあるようである。
nuget
nugetはWeb界隈から中々遠い部類に入るパッケージ管理ソフトウェアであるが、C#ばかり使っていた僕には最も馴染み深いのでここに記す。
C#やVBを使っている人からすればVS2010(?)あたりから搭載されたnugetは記憶に新しい。VSが標準とするパッケージ管理ソフトウェアである。
.Net系に関してはこれ以上のパッケージ管理ソフトウェアは見たことがないが、実はJavascript等のパッケージも解決してくれる。
- 対象言語・・・.Net系言語全般(C#,VB等)+JS,Typescript等
- 設定ファイル・・・XML(package.config)
- 公式サイト・・・https://www.nuget.org/
npm
Node.js用のパッケージ管理ソフトウェアのようである。Node.jsに縛られない様々なライブラリやツールをnpmを用いて可能であり、割と便利。
「npm install -global」とすれば、nugetなどとは違いコンソールでそのまま呼び出せるようになるのはコマンドラインツールとして洗練されている感が大きい。
- 対象言語・・・Node.jsがメイン
- 設定ファイル・・・json(package.json)
- 公式サイト・・・https://www.npmjs.com/
bower
Webフロント向けのパッケージ管理ソフトウェアのようである。jQueryやUnderscore.jsなどのブラウザ上で動作することが前提のライブラリ等がこれを用いて公開されている印象を受ける。
- 対象言語・・・主にJS
- 設定ファイル・・・json(bower.json)
- 公式サイト・・・http://bower.io/
bowerとnpmの違い
自分が最初に感じたのはbowerとnpmの境界線が不明瞭だということだ。npmとbowerはよく一緒に使われるような状況を見る。さらにはnpmには一部のフロントエンドのパッケージも公開されているし、それしか使わないならbowerは要らない子なんじゃないかと感じた。
しかし、これについて調べてみると様々な見解に触れることができた。
「npmとフロントエンドのパッケージ管理の未来」-- havelog.ayumusato.com
http://havelog.ayumusato.com/develop/others/e630-npm_meets_frontend.html
によれば以下のように書いてある。
現状の使い分けをおさらいをしておくと、次のような感じになる。
#npm
タスクランナー(Grunt/gulp)・モジュールシステム(browserify/webpack)・テストスイート(karma/testem)などの開発環境系の管理が npm の主なお仕事。インストールされたパッケージは node_modules 内に展開されて、CommonJS スタイルのモジュール管理から利用する。
本題につながる話としては、ブラウザで動くライブラリの一部は npm にも publish されている。
#Bower
npm が主に Node.js の世界であるのに対して、Bowr は jQuery や AngularJS、BackboneJS のようなブラウザの世界で動くライブラリを管理するのがお仕事。インストールされたパッケージは bower_components 内に展開されるが、モジュール管理の仕組みはないので他の手段でビルドしたり、bower_components 自体を公開ディレクトリ下に配置したりして扱う。
確かにnpmの使い道はライブラリ管理というよりライブラリ以外のツールの解決に使われる傾向はあったと感じていた。
npmがフロントエンドのライブラリ管理に向かない理由についても同ブログで述べられている。
Node.js は packageA の packageB@1.0.0 への依存と、packageC の packageB@0.9.0 への依存を両立できる。各パッケージのnode_modules にそれぞれのバージョンが展開されるから基本的には競合しないし、npm dedupe で多少整理する手段も用意される。
フロントエンドでは、異なるバージョンの jQuery を読み込むことは noConflict で回避できなくはないが、リソースを2重に呼び出すこと自体も看過できないロスになる可能性がある。CSSに至っては、Bootstrap の異なるバージョンを同時に読み込めばスタイルは容易に破壊される。
bowerと似ている物
bowerのようなフロントエンド用のライブラリ管理ソフトウェアについて調べてみるとほかにも様々な種類の類似ソフトウェアがあるようである。
とはいえ、少し見た限りではbowerと比べるとコミュニティは弱小感否めない印象を受けた。ここでは類似ソフトウェアのリンクの簡単な紹介にとどめる。
-
Component https://github.com/componentjs/component
-
Ender http://enderjs.com/
gem
jsのパッケージ管理の話から打って変わり、gemはRuby向けのパッケージ管理ソフトウェアである。
- 対象言語・・・Rubyが主
- 設定ファイル・・・(?)
- 公式サイト・・・https://rubygems.org/
タスクランナー系
ビルド時にユニットテストを一緒にやったり、コンパイルの前処理をしたり、実はWeb開発においては思っている以上に自分で自動化したほうがいい事はたくさんあります。それらをどのような順番で走らせるのか、あるいは組み合わせをタスクとして発行するのか、それがタスクランナーでしょうか。
Android開発時にGradleを僕は使っていました。Gradleはビルドツールという位置づけですので、依存関係解決もGradleの機能でできます。同時にビルドの手順をGradleを用いて記述できますが、このビルドの手順にあたるツールのようです。
Grunt
- 設定ファイル・・・JS(Gruntfile.js)
- 公式サイト・・・http://gruntjs.com/
gulp.js
よりGruntの設定ファイルを分かりやすく記述できることを目的としたタスクランナー。
- 設定ファイル・・・JS(gulpfile.js)
- 公式サイト・・・http://gulpjs.com/
Gruntとgulpの比較
gulpとGruntの比較においてどこも述べられているのがgulpのほうが設定ファイルが単純であるということである。gulpの方が後発であることを考えると、やはりこちらのほうが洗練されているのだろうか。
「Gruntに置き換わるか?新生ビルドシステム「gulp」v3.5.2入門」
http://re-dzine.net/2014/02/getting-started-with-gulp/
にはわかりやすい例が載っていた。
では実際にGruntとgulpそれぞれの設定ファイルの違いを見てみます。ここでは、twbs/bootstrap-sassの40個あるSCSSファイルの監視 → CSSファイルへのコンパイル → autoprefixerによるベンダープレフィックスの付与、という一連の流れを例にしてみます。
grunt.initConfig({
sass: {
dist: {
files: [{
cwd: 'sass',
src: 'bootstrap.scss',
dest: '.tmp/',
expand: true,
ext: '.css'
}]
}
},
autoprefixer: {
options: ['last 1 version'],
dist: {
files: [{
expand: true,
cwd: '.tmp/',
src: 'bootstrap.css',
dest: 'dist/css'
}]
}
},
watch: {
styles: {
files: ['sass/{,*/}*.scss'],
tasks: ['sass:dist', 'autoprefixer:dist']
}
}
});
grunt.registerTask('default', ['sass', 'watch']);
gulp.task('sass', function () {
gulp.src('sass/bootstrap.scss')
.pipe(sass())
.pipe(autoprefixer('last 1 version'))
.pipe(gulp.dest('dist/css'));
});
gulp.task('default', ['sass'], function() {
gulp.watch('sass/**/*.scss', ['sass']);
});
確かにこの差は大きい。なおかつ、gulpのほうが早く動作するといいます。