npm と gulp でフロントエンドライブラリを管理してリポジトリから消してみる


## 概要
npm と gulp を組み合わせて JavaScript ライブラリを管理する方法を紹介します。
普段 JavaScript をヘビーに使わず grunt, gulp などのタスクランナーを開発中にがっつり導入する気のない人を想定しています。

## 経緯
JavaScript のライブラリを bower で管理していて、install した js, css や WebFont などの assets を全てリポジトリにコミットしていました。

bower はライブラリをダウンロードしてきて自分で配置している頃に比べてバージョン管理できてる安心感があって良いなと思います。

実用上ほぼ不都合を感じていなかったのですが、しばらく運用してみるといくつか改善したい点が出てきました。

1. 実際は JavaScript をほとんど書いていないのに github の統計情報上は JavaScript の比率がかなり高くみえる
2. ライブラリのバージョンアップを伴う pull request のレビューが大変
3. エディタの File Finder 機能を使うとライブラリが検索対象になる

まあ、どれも瑣末なのですが、JavaScript ライブラリをリポジトリにコミットしなければ上記の問題は全て解決するのでは？と考えて実行してみました。

## ゴール
基本タスクランナーを使わない想定なので、以下でインストール完了を目指します。

```schell:Terminal
$ npm install
```

## 手順
npm の run-script から gulp を使います。そもそも npm を導入していない場合は `npm init` で `package.json` を用意してください。

### post-install から gulp を呼ぶ
以下を追記します。`gulpfile.coffee` だと設定ファイル然とした見栄えになって良いという理由で coffee も淹れることにしました。

```js:package.json
  "scripts": {
    ...
    "postinstall": "gulp"
  }
  ...
  "devDependencies": {
    "coffee-script": "1.9.3",
    "gulp": "3.9.0",
    "gulp-concat": "*",
    ...
  }
```


### 依存ライブラリを dependencies に書く
使いたいライブラリを package.json の dependencies に書きます。
下記サンプルは Angular.js と Bootstrap と Angular-UI Bootstrap に jQuery の組み合わせです。

```js:package.json
  "dependencies": {
    "angular": "1.3.15",
    "angular-resource": "1.3.15",
    "bootstrap": "3.3.4",
    "angular-ui-bootstrap": "0.12.1",
    "jquery": "2.1.4"
  }
```

### gulpfile.coffee をこさえる
`gulp-concat` でライブラリを連結します。minify するほどガチではないなあと考えて連結だけしました。今思うと単純に各ファイルをコピーしても良かったかなと思います。

```coffeescript:gulpfile.coffee
gulp.task 'default', -> ['concat', 'dist']

gulp.task 'concat', ['concat-js', 'concat-css']

# JS ライブラリ を vendors.js に連結する
gulp.task 'concat-js', ->
  gulp.src [
    'node_modules/angular/angular.js'
    'node_modules/jquery/dist/jquery.js'
    'node_modules/bootstrap/dist/js/bootstrap.js'
    'node_modules/angular-ui-bootstrap/ui-bootstrap-tpls.js'
  ]
  .pipe concat 'vendors.js'
  .pipe gulp.dest 'static/js/'

# CSS を bundle.css に連結する
gulp.task 'concat-css', ->
  gulp.src [
    'node_modules/bootstrap/dist/css/bootstrap.css'
    'static/example_other.css'
  ]
  .pipe concat 'bundle.css'
  .pipe gulp.dest 'static/css/'

gulp.task 'dist', ['dist-fonts', 'dist-css']

gulp.task 'dist-css', ->
  gulp.src 'node_modules/bootstrap/dist/css/*.map'
  .pipe gulp.dest 'static/css'

gulp.task 'dist-fonts', ->
  gulp.src 'node_modules/bootstrap/dist/fonts/*'
  .pipe gulp.dest 'static/fonts'

```

`static` 以下にファイルを吐く前提で書きました。

以上で、`npm install` でライブラリの js と css が連結され assets がコピーされるようになったと思います。

### .gitignore に追加する
node_modules や concat したファイルや assets を .gitignore に入れる。

```shell:.gitignore
node_modules/
static/js/vendors.js
static/css/bundle.css
static/css/*.css.map
static/fonts
```

あるいは既にコミット済みだったら `git rm -r` で消します。
## F.A.Q.
### gulp にした理由は？
npm の run-scripts だけでも連結したりコピーしたり出来るとは思います。ただ、それだと JSON にコメントが書けないので複雑になってきたときに困るかな？と思って gulp を選んでみました。`grunt` と比べても coffee-script と併用すれば `Gruntfile.js` よりすっきり収まるので結構好みだなという感想です。

### bower にしかライブラリが無いよ？
その場合は `gulp-bower` で管理しつつ `bower_components` 以下のファイルを concat で連結してます。
`bower_components` は .gitignore に含めます。

## まとめ
npm と gulp で、JavaScript ライブラリを管理できました。
地味ですがサーバサイドでは当たり前の、ライブラリのコードはリポジトリにコミットしない、を実現してみました。

[最近の npm のブログ](http://blog.npmjs.org/post/122450408965/npm-weekly-20-npm-3-is-here-ish)を読むと、フロントエンドのライブラリを npm で管理しようという動きがあるようです。そのうちこういうハックは不要になると期待したいです。