できるだけ楽ちんにCoffeeScriptだけでサーバとVue.jsを試す

# できるだけ楽ちんにCoffeeScriptだけでサーバとVue.jsを試す

久々にフロントエンドでUIをいろいろ試したくなり、Vue.jsを、JadeとCoffeeScriptで触ってみました。

Vue.jsは、AngularJSから双方向データバインディングだけ切り出したようなライブラリで、学習コストが低い割に使い勝手がよく、AngularJSの学習の入り口としてもいいらしいです。(AngularJSは2.0でごっそり変わるみたいだし、賛否両論だし、まだいいかな…)

* http://vuejs.org/guide/
* http://coffeescript.org/
* http://jade-lang.com/

## 方針

- できるだけ楽したいので、JavaScriptもHTMLも書きません。
  代わりにCoffeeScriptとJadeで書きます。かっこ閉じとか面倒ですよね。
  (ただし、ブラウザのDeveloper Toolでデバッグするので、
  JavaScriptもHTMLも、ある程度読める必要はあります)
- CSSも書きません。が、Bootstrapで楽して見た目はそれなりに…
- さくっと試したいので、gulpでコンパイルとかもしません。
  Vue.js, Bootstrap, jQueryは、CDNから直接ロードします。

ハマるところが少ないよう、できるだけシンプルな構成にしているので、
いろいろ書き換えながら勉強するのに向いてると思います。

この例では、サーバでAWSのインスタンス一覧を取得してキャッシュしておき、
フロントエンドでそれを取得して、インタラクティブにフィルタリングしています。

## フロントエンド側

Jadeは、Node.jsでよく使われるHTMLのテンプレートエンジンで、
CoffeScriptやYAML等と同様、インデントの深さでHTMLタグの階層構造を記述します。
classは`.`、idは`#`と、CSS的に書ける上に、
divだとタグ名も省略できたり、かなり読みやすくなります。

`title= title`とかは、Jadeのテンプレートの機能で、サーバ側でレンダリングされます。
`v-text`とか`{{}}`は、Vueによる拡張で、クライアント側でバインドされ、レンダリングされたりします。

```jade:views/index.jade
doctype html
html
  head
    meta(charset='utf-8')
    title= title
    link(rel='stylesheet',href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css')
    script(src='https://cdnjs.cloudflare.com/ajax/libs/vue/0.11.5/vue.min.js')
    script(src='http://code.jquery.com/jquery-2.1.3.min.js')
  body
    .container
      .masthead
        h1.text-muted= title
    #demo.container
      form.form-inline(role='form')
        input.form-control(v-model='searchText')
      div.text-muted(v-text='message')
      .table-responsive
        table.table.table-striped
          thead
            tr
              th Name
              th InstanceType
              th State
              th InstanceId
              th PrivateIpAddress
              th PublicIpAddress
          tbody
            tr(v-repeat='instances | filterBy searchText | orderBy field')
              td {{name}}
              td {{InstanceType}}
              td {{State.Name}}
              td {{InstanceId}}
              td {{PrivateIpAddress}}
              td {{PublicIpAddress}}
    .container
      .footer
        p &copy; Copyright kaz080, 2015

    script
      :coffee
        vm = new Vue
          el: '#demo'
          data:
            instances: []
            field: 'name'
            message: ''
        $.getJSON '/instances', (res) ->
          console.log JSON.stringify res, 0, 2
          for i in res
            continue unless i.Tags
            i.name = tag.Value for tag in i.Tags when tag.Key == 'Name'
          vm.$data.instances = res
          vm.$data.message = "Total #{res.length} instances"

    script(src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js')
```

## サーバ側

CoffeeScriptも、インデントで階層構造を表現することで`{}`を省略できたり、
引数の`()`を省略できたりと、JavaScriptの冗長な記述を不要にしてくれます。
(`->` だけでfunctionが書けたり、arrayやloop処理などもめちゃくちゃ楽です)

```coffeescript:app.coffee
express = require 'express'
http = require 'http'
aws = require 'aws-sdk'

app = express()
server = http.createServer app

app.set 'port', process.env.PORT || 3000
app.use express.static __dirname + '/public'
app.set 'views', __dirname + '/views'
app.set 'view engine', 'jade'

debug = (message) ->
  console.log message

# Configure libraries
process.env.AWS_PROFILE = process.env.AWS_DEFAULT_PROFILE
aws.config.update region: 'us-west-2'
ec2 = new aws.EC2()

# Start server
server.listen app.get 'port'
debug 'Start listening.'

# get HTML
app.get '/', (req, res) ->
  res.render 'index', { title: 'Express, Jade, Bootstrap, Vue, jQuery' }

# get JSON
instances = null
app.get '/instances', (req, res) ->
  if instances
    res.json instances
    return
  ec2.describeInstances {}, (err, data) ->
    debug JSON.stringify err if err
    instances = (r.Instances[0] for r in data.Reservations)
    res.json instances
```

サーバを起動し、http://localhost:3000/ にアクセス。

```bash
npm install express coffee-script jade aws-sdk
coffee app.coffee
```

## 感想

- やっぱりCoffeeScriptの方がRubyより楽ちんで速い
- 簡潔で読みやすく見通しよく書けるのって大事