GulpでAngularアプリのビルド自動化 Bower + Jade + Coffee + Less


最近 AngularJS (Angular Material) を始めました。
同じくこれから始める人向けに、現時点で動作する組み合わせの例として参考になれば幸いです。
よりベターなプラクティスがあれば教えていただけると嬉しいです！

#### versions
```sh
$ date
2015年 6月27日 土曜日 00時02分39秒 JST
$ node -v
v0.12.4
$ npm -v
2.10.1
$ bower -v
1.4.1
$ gulp -v
[00:04:24] CLI version 3.9.0
[00:04:24] Local version 3.9.0
```


# Code

#### bower.json (抜粋)

作成するアプリ向けのコンポーネントなので、あくまでご参考です。

```js
  "dependencies": {
    "angular": "~1.4.1",
    "angular-material": "~0.10.0",
    "angular-animate": "~1.4.1",
    "angular-aria": "~1.4.1",
    "angular-cookies": "~1.4.1",
    "angular-route": "~1.4.1",
    "file-saver": "*",
    "jquery": "~2.1.4",
    "underscore": "~1.8.3",
    "FileSaver": "*",
    "soundmanager2": "*"
  }
```

#### package.json (抜粋)

Gulp で利用するパッケージです。

```js
  "dependencies": {
    "gulp": "^3.9.0"
  },
  "devDependencies": {
    "bower": "^1.4.1",
    "coffee-script": "^1.9.3",
    "del": "^1.2.0",
    "express": "^4.13.0",
    "gulp-coffee": "^2.3.1",
    "gulp-concat": "^2.6.0",
    "gulp-if": "^1.2.5",
    "gulp-jade": "^1.0.1",
    "gulp-less": "^3.0.3",
    "gulp-ng-annotate": "^1.0.0",
    "gulp-nodemon": "^2.0.3",
    "gulp-slim": "^0.1.0",
    "gulp-uglify": "^1.2.0",
    "main-bower-files": "^2.8.2"
  },
```

#### gulpfile.js
```js
require('coffee-script/register');
require('./gulpfile.coffee');
```

#### gulpfile.coffee
```coffee
# gulpfile.coffee: build script for front assets
#
# gulp        - build assets
# gulp watch  - build assets continuously
# gulp server - start a server with assets and mocked APIs

sources =
  bower:  'bower.json'
  jade:   'app/*.jade'
  coffee: 'app/**/*.coffee'
  less:   'app/**/*.less'
  static: 'public/**/*'

bower       = require 'bower'
mbfiles     = require 'main-bower-files'
del         = require 'del'
gulp        = require 'gulp'
gulpif      = require 'gulp-if'
coffee      = require 'gulp-coffee'
concat      = require 'gulp-concat'
jade        = require 'gulp-jade'
less        = require 'gulp-less'
ngAnnotate  = require 'gulp-ng-annotate'
nodemon     = require 'gulp-nodemon'
uglify      = require 'gulp-uglify'

bowerfiles  = mbfiles()
dest_dir    = 'build/webapp/'

gulp.task 'default', ['clean'], ->
  gulp.start(
    'compile:bower'
    'compile:jade'
    'compile:coffee'
    'compile:less'
    'compile:static'
  )

gulp.task 'clean', (cb) ->
  del dest_dir, cb

gulp.task 'watch', ->
  gulp.watch sources.bower,  ['compile:bower']
  gulp.watch sources.jade,   ['compile:jade']
  gulp.watch sources.coffee, ['compile:coffee']
  gulp.watch sources.less,   ['compile:less']
  gulp.watch sources.static, ['compile:static']

gulp.task 'compile:bower', ->
  bower.commands.install().on 'end', ->
    isCss = (file) -> return file.path.substr(-4) == '.css'
    gulp.src bowerfiles
      .pipe gulpif(isCss, concat('components.css'), concat('components.js'))
      .pipe gulp.dest dest_dir

gulp.task 'compile:jade', ->
  gulp.src sources.jade
    .pipe jade {locals: {}}
    .pipe gulp.dest dest_dir

gulp.task 'compile:coffee', ->
  gulp.src sources.coffee
    .pipe coffee()
    .pipe ngAnnotate()
    .pipe uglify()
    .pipe concat 'app.js'
    .pipe gulp.dest dest_dir

gulp.task 'compile:less', ->
  gulp.src sources.less
    .pipe less()
    .pipe concat 'app.css'
    .pipe gulp.dest dest_dir

gulp.task 'compile:static', ->
  gulp.src sources.static
    .pipe gulp.dest dest_dir

gulp.task 'server', ['compile:apimock'], ->
  gulp.start 'watch', 'watch:apimock'
  nodemon
    script: 'build/apimock.js'
    watch: ['build/apimock.js', dest_dir]
    env:
      port: 8888
      webapp: "#{__dirname}/build/webapp/"

gulp.task 'watch:apimock', ->
  gulp.watch 'apimock.coffee', ['compile:apimock']

gulp.task 'compile:apimock', ->
  gulp.src 'apimock.coffee'
    .pipe coffee()
    .pipe gulp.dest 'build/'
```

#### apimock.coffee
```coffee
express = require 'express'
app = express()

app.use express.static process.env.webapp

app.get '/api/v1/hoge', (req, res) ->
  res.set 'Content-Type', 'application/json'
  res.send JSON.stringify
    price: 100

app.post '/api/v1/hoge', (req, res) ->
  res.set 'Content-Type', 'application/json'
  res.send JSON.stringify
    price: 200

app.listen process.env.port
```


# README

#### Install

```sh
$ npm install
```

#### Build

```sh
$ gulp
```

#### Run

```sh
$ gulp server
```


# Many thanks
- [JavaScript - AngularJSモダンプラクティス - Qiita](http://qiita.com/armorik83/items/5542daed0c408cb9f605)
    - CommonJS + Browserify スタイルは難しそうだったのでまだ手を付けていません。
- [npm + gulp + bower でビルド自動化 - GeekFactory](http://int128.hatenablog.com/entry/2014/07/02/004543)
    - こちらの記事の内容をほぼそのまま活用させていただいております。多謝。
- [gulp - main-bower-filesを活用する - Qiita](http://qiita.com/59naga/items/02ba2963fd957ef6cf36)
    - `gulp-bower-files`は`DEPRECATED`だったのでこちらで。