gulpを使用してwebpackで依存性を解決しつつCoffeeScriptをコンパイルする

今までは、JSの依存性の解決にはbrowserifyを使っていたんですけど、webpackの場合は複数ファイルの出力に対応していたり、js以外を扱うこともできるとのことで触ってみることにしました。

まずは、タイトルにある通りのことをやってみます。

# やりたいこと
以下のディレクトリ構成があるとします

```
┌ public
│      └ js
├ assets
│      └ coffee
├ gulpfile.coffee
├ webpack.config.coffee
└ package.json
```

assets/coffee 配下にcoffeescriptファイルが配置してあって、それをコンパイルして1ファイルに纏めてpublic/js配下に出力します。

# インストールしておくもの
package.jsonは以下のとおり（※name等は省略）

```package.json
{
  "devDependencies": {
    "coffee-loader": "^0.7.2",
    "coffee-script": "^1.10.0",
    "gulp": "^3.9.1",
    "gulp-load-plugins": "^1.2.2",
    "gulp-webpack": "^1.5.0",
    "gulp-webserver": "^0.9.1",
    "path": "^0.12.7"
  }
}
```

# 設定ファイル
まず、webpackの設定をwebpack.config.coffee にかきます。

```webpack.config.coffee
webpack = require('gulp-webpack').webpack                     
path    = require 'path'                                      
                                                              
current = process.cwd()                                       
                                                              
module.exports = {                                            
                                                              
  output:                                                     
    filename: 'app.js'  # 出力するファイル名                                       
                                                              
  resolve: {                                                  
    extensions: ['', '.js', '.coffee']  # requireする際に、拡張子を省略するための設定                        
    root: path.join(current, './assets/coffee')  # require時にファイルを検索する際のrootパス               
  }                                                           
                                                              
  module:                                                     
    loaders: [                                                
      {test: /\.coffee$/, loader: 'coffee-loader'}  # coffeescriptをコンパイルするための設定            
    ]                                                         
}                                                             
```

次にgulpfile.coffee

```gulpfile.coffee
gulp = require 'gulp'
$    = do require 'gulp-load-plugins'

gulp.task 'build', ->
  gulp.src './assets/coffee/**/*.coffee'  # coffeescriptの格納場所
  .pipe $.webpack require './webpack.config.coffee'  # webpack.config.coffeeの指定
  .pipe gulp.dest './public/js'  # 出力ディレクトリ

```

# 動かしてみる
サンプル用に以下のファイルを用意します。

``` assets/coffee/common.coffee
class Common
  @echo: (str) ->
    console.log str

module.exports = Common
```

``` assets/coffee/hoge.coffee
window.sample = window.sample || {}
Common = require 'common'

class Hoge
  constructor: () ->

  init: () ->
    Common.echo 'hoge'

window.sample.Hoge = Hoge
```

で以下をコマンドを実行

```
$ gulp build
```

すると、「public/js」配下にapp.jsが出力されます。
で、出力されたapp.jsを適当なhtmlに読み込ませると、インラインスクリプトからHogeクラスを使用できます。

```html
<script src="public/js/app.js"></script>
<script>
  new sample.Hoge().init()  // コンソールに"hoge"と表示される
</script>
```

# ファイルをそれぞれコンパイルする場合
上記のサンプルでは、複数CoffeeScriptを1つのJSファイルにしていますが、個別にしたい場合は以下のように設定ファイルを記入

```webpack.config.coffee
webpack = require('gulp-webpack').webpack
path    = require 'path'

current = process.cwd()

module.exports = {

  # entryポイントを設定(複数設定可)
  entry:
    sample:           './assets/coffee/sample.coffee'
    'common/sample2': './assets/coffee/common/sample2.coffee'

  # sample.coffee  ⇒ sample.js
  # sample2.coffee ⇒ common/sample2.js
  # として出力される
  output:
    filename: '[name],js'

  resolve: {
    extensions: ['', '.js', '.coffee']
    root: path.join(current, './assets/coffee')
  }

  module:
    loaders: [
      {test: /\.coffee$/, loader: 'coffee-loader'}
    ]
}
```

# 共通でrequireしておきたい場合
上記のhoge.coffeeではcommon.coffeeをrequireしているが共通で使用するモジュールをわざわざわ各CoffeeScriptにrequireと書くのが面倒なので、一律requireしたい場合は以下の設定を追加する

```webpack.config.coffee
webpack = require('gulp-webpack').webpack                     
path    = require 'path'                                      
                                                              
current = process.cwd()                                       
                                                              
module.exports = {                                            
                                                              
  output:                                                     
    filename: 'app.js'                                
                                                              
  resolve: {                                                  
    extensions: ['', '.js', '.coffee']
    root: path.join(current, './assets/coffee')
  }                                                           
                                                              
  module:                                                     
    loaders: [                                                
      {test: /\.coffee$/, loader: 'coffee-loader'}
    ]

  # 以下を追加
  plugins: [
    new webpack.ProvidePlugin(
      Common: 'common', # common.coffeeをCommonという名前で共通でrequireする
      $: 'jquery', # 自作のモジュールだけでなく'jquiry'等のnode_modules配下のモジュールも指定可能
    )
  ]
```

上記のようにしておくと、各CoffeeScriptで「Common = require 'common'」のように書かなくてもCommonや$を参照できるようになる

# その他
上記のサンプルだと、HTMLからクラスを呼ぶために「hoge.coffee」でwindowオブジェクトを使用してるんだけど他にいい方法はないものか。。。