Backbone.js + es6(Babel) + WebPack を試す


## はじめに
[Backbone.js](http://backbonejs.org/)のアプリを作る上で、es6 + [WebPack](http://webpack.github.io/)を使って試してみた。ソースは[こちら](https://github.com/muraken720/es6-backbone)。
## コンセプト
- Backbone.jsをes6([babel](https://github.com/babel/babel))を使って書く
- es6のmoduleを使ってソースを分割する
- es6のclassを無理して使わずに、Backboneのextendをそのまま使い、[Enhanced Object Literals](https://github.com/lukehoban/es6features#enhanced-object-literals)で書く
- テンプレートには[mustache](http://mustache.github.io/)を使う
- テストは[power-assert](https://github.com/power-assert-js/power-assert) ([espower-babel](https://github.com/power-assert-js/espower-babel))を使ってes6で書く
- WebPackは[hjs-webpack](https://github.com/HenrikJoreteg/hjs-webpack)を使う
- 依存関係の解決はBowerなどを使わずに、npm module (CommonJS)で統一する

## app.js
エントリポイントとなるapp.js

``` javascript:app.js
import $ from 'jquery'
import MainPage from './pages/main'
import Me from './models/me'

require('./styles/main.styl')

$(() => {
  window.app = {
    init() {
      this.me = new Me({name: 'muraken720', age: 25})
      this.mainPage = new MainPage({el: $('.container'), model: this.me})
      this.mainPage.render()
      //Backbone.history.start();
    }
  }

  app.init();
})
```

cssはstylusを使ってる。

``` stylus:styles/main.styl
@import 'yeticss'
```

## View
Viewのテンプレートにはmustacheを使う。WebPackのmustache-loaderを使って、htmlファイルをテンプレートにしている。WebPackの設定については後で出てくる。

``` html:pages/main.html
<div>
  <h1>Hello {{name}}!</h1>
</div>
```

``` javascript:pages/main.js
import {View} from 'backbone'

const mainTemplate = require('./main.html')

export default View.extend({
  template: mainTemplate,

  initialize () {
    this.listenTo(this.model, "change", this.render);
  },

  render() {
    this.$el.html(this.template(this.model.attributes))
    return this
  }

})
```

## Model
Modelを定義してみる。こちらはテストコードから試す。

``` javascript:models/me.js
import {Model} from 'backbone'

export default Model.extend({
  defaults: {
    name : '',
    age : 0
  },

  say() {
    return 'Hello ' + this.get('name')
  }
})
```

power-assertを使ったテストコードはこちら。es6で書いてみる。

``` javascript:app_test.js
import assert from 'power-assert'
import {describe, it} from 'mocha'

import {Model, Collection} from 'backbone'

import Me from '../src/models/me'

describe('Model', () => {
  it('default new', () => {
    let obj = new Model()

    obj.set({name: 'Murata'})
    obj.set({age: 20})

    assert(obj.get('name') === 'Murata')
    assert(obj.get('age') === 20)
  })

  it('option new', () => {
    let obj = new Model({name: 'Kenichiro', age: 30})

    assert(obj.get('name') === 'Kenichiro')
    assert(obj.get('age') === 30)
  })

  it('model extend', () => {
    let obj = new Me()
    obj.set({name: 'Murata', age: 15, id: 101})

    assert(obj.id === 101)
    assert(obj.get('name') === 'Murata')
    assert(obj.get('age') === 15)
  })

  it('say method', () => {
    let obj = new Me()
    obj.set({name: 'Murata', age: 15, id: 101})

    assert(obj.say() === 'Hello Murata')
  })

})
```

## WebPack(hjs-webpack)の設定
[hjs-webpack](https://github.com/HenrikJoreteg/hjs-webpack)を使って、index.htmlとして返すhtmlを定義する。後は、mustache-loaderの設定も追加した。

``` javascript:webpack.config.js
var getConfig = require('hjs-webpack')

var config = getConfig({
  in: 'src/app.js',
  out: 'public',
  clearBeforeBuild: true,
  html: function (data) {
    return {
      'index.html': data.defaultTemplate({html: '<div class="container"><h1>Hello World!</h1></div>'})
    }
  }
})

config.module.loaders.push({
  test: /\.html$/,
  loader: 'mustache?minify'
})

module.exports = config
```

## package.jsonの設定
npm start で webpack-dev-server を動かし、その際のsource-mapの指定を見やすく（inline-source-map）する。

``` javascript:package.json（抜粋）
  "scripts": {
    "start": "webpack-dev-server --devtool inline-source-map",
    "build": "webpack",
    "deploy": "surge -p public -d somedomain.surge.sh",
    "check": "standard",
    "test": "mocha --compilers js:espower-babel/guess test/**/*.js",
    "yolo": "npm run build && npm run deploy"
  }
```
## 感想
- module分割とimportによる利用がシンプルに書けて良い感じ。
- es6のclassを使って書くと自然な感じがしないので、Backboneのextendと[Enhanced Object Literals](https://github.com/lukehoban/es6features#enhanced-object-literals)で書くのは、無理なく書ける。
- [hjs-webpack](https://github.com/HenrikJoreteg/hjs-webpack)便利。
- [power-assert](https://github.com/power-assert-js/power-assert)便利。