bowerと仲良くなる


bowerを使っているのに素で

```html
<script src="/bower_components/angular/angular.js"></script>
```
いちいちこういうコード書いてる人、いませんよね。bowerを使えるなら自動で挿入(インジェクション)すべきです。

## main-bower-filesを活用すべし
しばらくgruntでgrunt-wiredepを使っていたんですが、useminに脳を焼かれたためGrunt自体やめました。Gulpでもwiredepのストリームを使うこともできますが、concatが辛めです。main-bower-filesを使いましょう。

# 実践
実際に動かしている構成に近づけようとしたら余計なものが結構入ってきてしまった感があるが、気にしない。

ちなみに本サンプルは
<https://github.com/endaaman/main-bower-files-is-nice>
に公開してあります。


```text:サンプル構成
.
├── .bowerrc
├── bower.json
├── gulpfile.coffee
├── karma.conf.coffee
├── node_modules
│   └── [略]
├── package.json
├── public
│   └── bower_components
└── src
    ├── app.coffee
    ├── index.jade
    └── test
        └── app.coffee
```

## Gulpで使う
index.jadeをindex.htmlにコンパイルして、開発時はbower_componentsから直接、プロダクションではconcatして、インジェクションしてみる。

サンプルでは、

```bower.json
{
  "name": "example",
  "dependencies": {
    "angular": "~1.2.26",
    "angular-resource": "~1.2.26"
  },
  "devDependencies": {
    "angular-mocks": "~1.2.26"
  }
}

```


```json:package.json
{
  "scripts": {
    "test": "./node_modules/karma/bin/karma start"
  },
  "devDependencies": {
    "coffee-script": "^1.8.0",
    "del": "^0.1.3",
    "gulp": "^3.8.8",
    "gulp-coffee": "^2.2.0",
    "gulp-concat": "^2.4.1",
    "gulp-inject": "^1.0.2",
    "gulp-jade": "^0.8.0",
    "karma": "^0.12.23",
    "karma-coffee-preprocessor": "^0.2.1",
    "karma-jasmine": "^0.1.5",
    "karma-phantomjs-launcher": "^0.1.4",
    "main-bower-files": "^2.0.0"
  }
}
```


```jade:index.jade
doctype html
html(ng-app="exampleApp")
    meta(charset="utf-8")
    body
        <!-- bower:js -->
        <!-- endinject -->
        <!-- inject:js -->
        <!-- endinject -->
```

という感じだとする。


```CoffeeScript:gulpfile.coffee
g = require 'gulp'
jade = require 'gulp-jade'
inject = require 'gulp-inject'
concat = require 'gulp-concat'
coffee = require 'gulp-coffee'
del = require 'del'
bowerFiles = require 'main-bower-files'

conf =
    src: 'src'
    dest: 'public'
    prod: false
    bowerDir: 'public/bower_components'


g.task 'clean', ->
    del [
        "#{conf.dest}/**/*"
        "!#{conf.bowerDir}"
        "!#{conf.bowerDir}/**/*"
    ]

g.task 'coffee', ['clean'], ->
    g.src "#{conf.src}/*.coffee"
    .pipe coffee()
    .pipe g.dest "#{conf.dest}/"

g.task 'build:bower', ->
    if conf.prod
        g.src bowerFiles()
        .pipe concat('_vendor.js')
        .pipe g.dest("#{conf.dest}/")

g.task 'index', ['build:bower', 'coffee'], ->
    ignores = ['public/', 'client/']

    t = g.src "#{conf.src}/index.jade"
    .pipe jade pretty: not conf.prod
    if not conf.prod
        t.pipe inject(
            g.src(bowerFiles(),
                    base: conf.bowerDir
                    read: false),
                ignorePath: ignores
                name: 'bower'
        )
    t.pipe inject(
        g.src("#{conf.dest}/*.js", read: false),
            ignorePath: ignores
    )

    t.pipe g.dest "#{conf.dest}/"


g.task 'build', ['index']

g.task 'prod', ->
    conf.prod = true

g.task 'default', ['build']
```
venoder.jsだとapp.jsより後にインジェクションされてしまうため、本来なら順番をちゃんと指定するところだけど面倒だから、結合したファイルを_vendor.jsという名前にしている。

タスクは

* `gulp clean` public/以下bower_components以外を掃除
* `gulp build`(または`gulp`) で開発用ビルド
* `gulp prod build` でプロダクションビルド

になる。

`gulp-inject`の作者が「bowerに対しては`main-bower-files`を使うといいよ！」と言っているだけあって、楽ちんです。結合も楽勝。
Gulpで`wiredep`を使うと`gulp-inject`とは別でインジェクションされてしまい、少し気持ち悪いです。結合もやりにくい。

## Karmaでも使える
というか、これが言いたくて書き始めた。

```CoffeeScript:karma.conf.cofee
module.exports = (config) ->
    bowerFiles = require 'main-bower-files'

    files = [
        'src/**/*.coffee'
    ]
    files = bowerFiles(includeDev: true).concat files

    config.set
        basePath: ''
        frameworks: ['jasmine']
        files: files
        exclude: []
        preprocessors:
            'src/**/*.coffee': ['coffee']

        reporters: ['progress']
        port: 9876
        colors: true
        logLevel: config.LOG_INFO
        autoWatch: false
        browsers: ['PhantomJS']
        singleRun: true
```

includeDevを指定することでdevDependenciesも含めることができます。なので、KarmaのコンフィグにつかってもOKです。
これは使うべきです。というか、使わない手はありません。

```CoffeeScript:src/app.coffee
'use strict'

angular.module 'exampleApp', [
    'ngResource'
]
.factory 'Add16', ->
    (i)->
        i + 16

.run (Add16)->
    console.log 'Add(3): ' + Add16(3)
    console.log 'Add(12): ' + Add16(12)
```

```CoffeeScript:src/test/app.coffee
'use strict'

describe 'Add16', ->
    Add16 = null
    beforeEach ->
        module 'exampleApp'
        inject ($injector)->
            Add16 = $injector.get 'Add16'

    it ->
        expect(Add16(14)).toBe 30

```
`angular-mocks`がちゃんと含まれているので、テストも通ります。

## CSSとかfontとかは守備範囲外
それでも個人的には問題になりません。というのも、CSSは生のCSSで使うことがほぼなく、大体LESSやSASS/SCSSで使うからです。この場合はインクルードパスをbowerにも通して、インポートやらで宣言を手元のCSSに引き込めばOKです。
fontは、minifyする必要がないのでbower_componentsをそのまま公開するか、公開しないならコピーしてもいいでしょう。そもそもfontsを扱うパッケージなどごく一部なので、苦にならないと思います。