wiredep, gulp-injectでlink, scriptをhtmlに自動注入

最近は`gulp`や`grunt`でビルドプロセスを自動化していかないとやってられない、というような流れになってきている気がしますが、`gulp`も`grunt`もいろんなライブラリが出まくっていて、一つ覚えたと思ったらもう新しくてさらに効率のいいライブラリが出てきたりしてますよね。。。と、愚痴を言っていても仕方ないのですが、今回は`link`タグとか`script`タグを自動で注入(`inject`)してくれる`gulp`のライブラリ、`wiredep`と`gulp-inject`の基本的な使い方について検証したのでまとめます。
**指摘事項や、「こうしたらほうがいいよ？」などありましたら遠慮無くコメント欄やメッセージなどで気軽に教えていただけると喜びますm(__)m**

# はじめに
まず、下のようなページがあったとします。

```html
<html>

<head>
  <link rel="stylesheet" href="../../bower_components/bootstrap/dist/css/bootstrap.css" />
  <link rel="stylesheet" href="../../bower_components/font-awesome/css/font-awesome.css" />
  <link rel="stylesheet" href="styles/app.css">
</head>

<body>
  <div id="main-region"></div>
</body>

<script src="../../bower_components/react/react.js"></script>

<script src="app/app.js"></script>

</html>
```

すごいシンプルなので、ここからは問題はあまり見えてこないんですけど、`bower`使って便利ライブラリをいろいろとインストールしていって、`css`やら`script`やらが増えてくると、いちいち自分で`index.html`に書いてられないですよね？おまけにこれに各アプリケーション特有の`css`と`script`も増えていくのがほとんどのケースだと思います。これを全部管理するっていうのは人間のやることじゃない。って考える人は世の中にいっぱいいて、そうなるとやっぱり便利ツールは出現するんです。そこで登場するのが`wiredep`と`gulp-inject`。

こんなことをします。
![wiredep.gif](https://qiita-image-store.s3.amazonaws.com/0/38528/f65da32b-fa6b-9289-fe65-c6ff46d80d73.gif "wiredep.gif")

## ライブラリについて
### wiredep
> Wire Bower dependencies to your source code.

と、[github](https://github.com/taptapship/wiredep)で書かれているように、`bower install --save`したライブラリを`html`に自動で注入してくれるのが`wiredep`です。`dependencies`を見ながら`html`に注入してくれるので、（やや難がありますが）注入順についても意識しなくても良いという特徴があります。

### gulp-inject
> A javascript, stylesheet and webcomponent injection plugin for Gulp, i.e. inject file references into your index.html

と、[github](https://github.com/klei/gulp-inject)に書かれているように、`bower`に特化せず、`css`やら`script`やらを注入できるのが`gulp-inject`（多分）。 **依存関係とかを勝手にいい感じにやってくれる** って機能はないはずなので、今回は`gulp-inject`をアプリ特有の`css`や`script`に使おうと思います。

# 下準備
あらかじめ入れてある前提で話を進める`npm package`は`gulp`（もちろん）と`gulp-load-plugins`です。
今回のように小規模なサンプルの場合`gulp-load-plugins`はどう考えても必要ないけど、たいていの場合私は`gulp-*`系なライブラリを多用するので`gulp-load-plugins`を使います。これについては詳しく説明しません。ってなわけでインストールしておきます。

```bash
npm install --save-dev gulp gulp-load-plugins
```

`wiredep`と`gulp-inject`もインストールしちゃいましょう。

```bash
npm install --save-dev wiredep gulp-inject
```

# wiredep関連の作業

## html編集
`bower`経由でインストールしているライブラリのタグを`css`なら`bower:css`で、`script`なら`bower:js`で下のように囲んで、元のタグは消しちゃいます。ここに`wiredep`が自動注入してくれるようになるからです。

```html:src/client/index.html
<html>

<head>
  <!-- bower:css -->
  <!-- endbower -->
  <link rel="stylesheet" href="./styles/app.css">
</head>

<body>
  <div id="main-region"></div>
</body>

<!-- bower:js -->
<!-- endbower -->
<script src="./app/app.js" charset="utf-8"></script>

</html>
```

## gulpfile.js編集
それでは`gulpfile.js`の編集をします。書きっぷりとしては下のように書いておけば（たいていの場合）完了です。

```js:gulpfile.js
gulp.task('wiredep', function() {
  var wiredep = require('wiredep').stream;

  return gulp
    .src('./src/client/index.html')
    .pipe(wiredep()) // wiredep bower dependencies
    .pipe(gulp.dest('./src/client')) // output the index.html
})
```

ただし、今回の例の場合うまくいきません。仮に`gulp wiredep`と実行してもタスクは完了して何も注入されていないことに気づきます。

何故かと言うと、`wiredep`の仕組み上、注入するための情報が不足しているからです。
`wiredep`が自動注入する際に参考にしている情報は各ライブラリの`.bower.json`の`main`の内容と`dependencies`の内容です。
今回使っている`bootstrap`の`.bower.json`を見ると、

```js
// 割愛

"main": [
  "less/bootstrap.less",
  "dist/js/bootstrap.js"
],

// 割愛

"dependencies": {
  "jquery": ">= 1.9.1"
},
```

となっており、注入してほしい`dist/css/bootstrap.css`が記述されていません。こんな時は自分の`bower.json`に明示的に情報を付加してあげる必要があります。書きっぷりは下のような感じになります。

```js:bower.json
"overrides": {
  "bootstrap": {
    "main": "dist/css/bootstrap.css",
    "dependencies": {}
  },
  "font-awesome": {
    "main": "css/font-awesome.css"
  }
}
```

`overrides`の下に`ライブラリ名: {プロパティ名: 与えたい値}`という具合で情報を増やしてあげます。今回は`bootstrap`の`dependencies`である`jquery`も使いたくなかったので明示的に`dependencies`を空オブジェクトにしています。ここのそのままにしていると`bower:js`で囲まれている箇所に`jquery`が意図せず注入されてしまいます。
これで`wiredep`関連の自動化は完了。`gulp wiredep`で`bower`関連のライブラリが注入されるはずです。

# gulp-inject関連の作業
それでは、各アプリ特有の`css`と`script`も注入できるようにします（多くの場合`app.js`だったり`app.css`だったりするファイルです）。要領は`wiredep`のときと同様ですが、囲むタグを`css`の場合は`inject:css`で、`script`の場合は`inject:js`とします。
下のようになるはずです。これで手動で書くタグはなくなりましたね！

## htmlの編集
```html:src/client/index.html
<html>

<head>
  <!-- bower:css -->
  <!-- endbower -->
  <!-- inject:css -->
  <!-- endinject -->
</head>

<body>
  <div id="main-region"></div>
</body>

<!-- bower:js -->
<!-- endbower -->
<!-- inject:js -->
<!-- endinject -->

</html>
```

## gulpfile.jsの編集
先ほどの`wiredep`タスクにちょっとコードを足します。

```js:gulpfile.js
gulp.task('wiredep', function() {
  var wiredep = require('wiredep').stream;

  return gulp
    .src('./src/client/index.html')
    .pipe(wiredep()) // wiredep bower dependencies
    .pipe($.inject(gulp.src(['./src/**/*.js', './src/**/*.css']), {
      relative: true // no need for the './src/client' part
    }))
    .pipe(gulp.dest('./src/client')) // output the index.html
})
```

`gulp-load-plugins`を使っていて、かつそれを`$`として`require`しているので`gulp-inject`は`$.inject`でアクセス可能になってます。対象ファイルはとりあえず`src`配下の`css`と`js`としてます。そして、オプションなしでこのまま実行すると`link`や`script`タグが`./src/client`からパスを初めてしまうので、`index.html`からみた相対パスを注入してもらうように`relative: true`というオプションを渡しています。
以上で完了です。これで`gulp wiredep`を実行したら`index.html`に自動で`link`や`script`タグが注入されるようになります。

# それぞれのソースの最終形

```html:src/client/index.html
<html>

<head>
  <!-- bower:css -->
  <!-- endbower -->
  <!-- inject:css -->
  <!-- endinject -->
</head>

<body>
  <div id="main-region"></div>
</body>

<!-- bower:js -->
<!-- endbower -->

<!-- inject:js -->
<!-- endinject -->

</html>
```

```js:gulpfile.js
var gulp = require('gulp');
var $ = require('gulp-load-plugins')({
  lazy: true
});

gulp.task('wiredep', function() {
  var wiredep = require('wiredep').stream;

  return gulp
    .src('./src/client/index.html')
    .pipe(wiredep()) // wiredep bower dependencies
    .pipe($.inject(gulp.src(['./src/**/*.js', './src/**/*.css']), {
      relative: true // no need for the './src/client' part
    }))
    .pipe(gulp.dest('./src/client')) // output the index.html
})
```

```json:bower.json
{
  "name": "wiredep-inject-starter",
  "version": "0.0.0",
  "homepage": "https://github.com/kenfdev/wiredep-inject-starter",
  "authors": [
    "Ken Fukuyama <kenfdev@gmail.com>"
  ],
  "license": "MIT",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "bootstrap": "~3.3.5",
    "font-awesome": "~4.4.0",
    "react": "~0.13.3"
  },
  "overrides": {
    "bootstrap": {
      "main": "dist/css/bootstrap.css",
      "dependencies": {}
    },
    "font-awesome": {
      "main": "css/font-awesome.css"
    }
  }
}
```

# 課題
課題というか、このサンプルだけでは足りていないことは、
* アプリ特有の`script`の依存関係を考えた順番の注入ができていない
* 実際は`css`や`js`のビルドプロセスが存在するため、このタスク単体では実務では使えない。（依存タスクをもっと作る必要あり）
などなど、まだまだたくさんあります。
が、とりあえずは`wiredep`と`gulp-inject`の雰囲気がつかめたのでよしとしようかと。

# おまけ
[wiredep-inject-starter](https://github.com/kenfdev/wiredep-inject-starter)として今回のソースを上げています。