Play Framework2.3でsbt-rjs,sbt-less ( sbt-digest, sbt-jshint, sbt-gzip)を使ってTwitter Bootstrap3.1.1を使ったプロジェクトを作る。

PlayFramework2のバージョン2.3がリリースされたので、
新機能のsbt-webを使ってTwitter Bootstrap3.1.1を使ったプロジェクトを作った際のメモです。

[サンプル](https://github.com/satoshi-m8a/play23-bootstrap)

# やったこと #
 1. plugins.sbtの設定
 2. build.sbtの設定
 3. デフォルトのjshint設定では心許ないのでsbt-jshintで自前の.jshinrcを読み込む
 4. main.jsにrequirejsの設定を書く
 5. main.lessでbootstrap.lessを読み込む

# ハマったところ #
 * sbt-digestでフィンガープリントが表示されない。
 * require.jsのパスの指定の仕方。
 * sbt-jshintとsbt-rjsを一緒に使うと'requirejs'や'require'がglobalで定義されているとjshintに怒られる。


## 1.plugins.sbtの設定  ##

```scala:project/plugins.sbt
resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"

// The Play plugin
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.0")

// web plugins

addSbtPlugin("com.typesafe.sbt" % "sbt-jshint" % "1.0.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.1")

addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.0.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-gzip" % "1.0.0")

addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.0.0")

```

## 1.build.sbtの設定  ##
```scala:build.sbt
name := """play-bootstrap"""

version := "1.0-SNAPSHOT"

lazy val root = (project in file(".")).enablePlugins(PlayScala)

scalaVersion := "2.11.1"

libraryDependencies ++= Seq(
  jdbc,
  anorm,
  cache,
  ws,
  "org.webjars" % "jquery" % "2.1.1",
  "org.webjars" % "bootstrap" % "3.1.1-1"
)

includeFilter in(Assets, LessKeys.less) := "*.less"

excludeFilter in(Assets, LessKeys.less) := "_*.less"

pipelineStages := Seq(rjs, digest, gzip)
```

アセットパイプラインは`activator run` では動かないので
動かすときは`activator start`で確認する。
jsやcss,htmlのファイルの先頭にmd5が付与されているはず。
例：`/assets/javascripts/bd7ab1c5b4a89be273f1a6bcb588f163-main.js`
レスポンスヘッダの
Content-Encodingがgzipになっているはず。



## 3. デフォルトのjshint設定では心許ないのでsbt-jshintで自前の.jshinrcを読み込む ##
.jshintrcを[jshint本家Githubのサンプル](https://github.com/jshint/jshint/blob/master/examples/.jshintrc)から拝借。
コメントとかが残っているとエラーが起こるので削除し、プロジェクトルートに置く。

```js:.jshintrc
{
    "maxerr": 50,
    "bitwise": true,
    "camelcase": false,
    "curly": true,
    "eqeqeq": true,
    "forin": true,
    "immed": false,
    "indent": 4,
    "latedef": false,
    "newcap": false,
    "noarg": true,
    "noempty": true,
    "nonew": false,
    "plusplus": false,
    "quotmark": false,
    "undef": true,
    "unused": true,
    "strict": true,
    "maxparams": false,
    "maxdepth": false,
    "maxstatements": false,
    "maxcomplexity": false,
    "maxlen": false,
    "asi": false,
    "boss": false,
    "debug": false,
    "eqnull": false,
    "es5": false,
    "esnext": false,
    "moz": false,
    "evil": false,
    "expr": false,
    "funcscope": false,
    "globalstrict": false,
    "iterator": false,
    "lastsemic": false,
    "laxbreak": false,
    "laxcomma": false,
    "loopfunc": false,
    "multistr": false,
    "proto": false,
    "scripturl": false,
    "shadow": false,
    "sub": false,
    "supernew": false,
    "validthis": false,
    "browser": true,
    "couch": false,
    "devel": true,
    "dojo": false,
    "jquery": false,
    "mootools": false,
    "node": false,
    "nonstandard": false,
    "prototypejs": false,
    "rhino": false,
    "worker": false,
    "wsh": false,
    "yui": false,
    "globals": {}
}
```

##  4. main.jsにrequirejsの設定を書く ##

```js:app/javascripts/main.js
/*global require, requirejs */

requirejs.config({
    paths: {
        jquery: '../lib/jquery/jquery',
        bootstrap: '../lib/bootstrap/js/bootstrap'
    },
    shim: {
        jquery: {
            exports: '$'
        },
        bootstrap: {
            deps: ['jquery']
        }
    }
});

require(["jquery", "bootstrap"], function ($) {
    "use strict";

    console.log($.fn.jquery);
});
```

## 5. main.lessでbootstrap.lessを読み込む ##

```css:app/stylesheets/main.less
@import './lib/bootstrap/less/bootstrap';

body {
  color: #000;
}
```
WebJarsで取り込んだbootstrap.lessへのパスは
`./lib/bootstrap/less/bootstrap`
となる。


### sbt-digestでフィンガープリントが表示されない? ###
assetsの指定の仕方を
`@routes.Assets.at("stylesheets/main.css")`
から
`@routes.Assets.versioned("stylesheets/main.css")`
に変更

例：

```html
 <link rel="stylesheet" media="screen" href="@routes.Assets.versioned("stylesheets/main.css")">
```

routesファイルを変更

```:conf/routes
GET /assets/*file  controllers.Assets.at(path="/public", file)
```
から

```:conf/routes
GET /assets/*file  controllers.Assets.versioned(path="/public",  file: Asset)
```
へ書き換える。
この時, `file:Assets`と書くべきところを`file`と書いていて、15分無駄にしました。

### require.jsのパスの指定の仕方。 ###

```html:views/main.scala.html
 <script data-main="@routes.Assets.versioned("javascripts/main.js")" type="text/javascript" src="@routes.Assets.versioned("javascripts/require.js")"></script>
```
と`javascripts/require.js`を指定すればOK。


libraryDependencies に `"org.webjars" % "requirejs" % "2.1.11-1"`を追加して、`@routes.Assets.versioned("lib/requirejs/require.js")`としているサンプルもありますが、必要無いっぽいです。

### sbt-jshintとsbt-rjsを一緒に使うと'requirejs'や'require'がglobalで定義されているとjshintに怒られる。 ###

エラーが出た.jsファイルの先頭のコメントに
`/*global require, requirejs */`
と書く。

# まとめ #
sbt-rjsとwebjarsをいっしょにに使うとjsdelivrのurlが自動で指定されるようになっていてうれしかったです。

# 課題,疑問点 #
 * jsdelivrのurlへの書き換えの無効化
 * bowerを使わない理由
 * WebJarsの管理は誰がやってるの？自動で最新版に追従する仕組みがあるの？