自己紹介

  • よくrpscalaにいる
  • 最近PureScriptに夢中
  • 来月から銀座の某D社で働くらしい

Play 2.3リリース間近!

  • Play 2.3.0-RC2 is released
  • sbt 0.13.5-RC5 is released
  • 6月中には正式リリースしそう!?

Play 2.3の主な変更点

  • アセット(JavaScript、CSS)関連がsbt-webに移行
  • playコマンドの廃止、activatorコマンドに移行
  • Twirl(Scalaテンプレート)、WSの分離
  • Java 8対応、Scala 2.11対応
  • Anormの改善(String Interpolationの導入など)
  • WebSocketの改善(アクター化など)
  • 詳しくは What’s new in Play 2.3

sbt-webとは?

  • Play 2.3の最大の変更点
  • アセットの機能をPlay本体から分離
  • sbt 0.13.5のAutoPlugin機能を使って、複数のプラグインから構成されている

sbt 0.13.5のAutoPlugin

AutoPluginのコード例

object SbtGzip extends AutoPlugin {
  override def requires = SbtWeb
  override def trigger = AllRequirements
  object autoImport {
    val gzip = TaskKey[Pipeline.Stage]("gzip-compress", "Add ...")
  }
  import autoImport._
  override def projectSettings: Seq[Setting[_]] = Seq(
    gzip := Def.task {
      ...
    }.value
  )
}

AutoPluginの使用例

// project/plugins.sbt
addSbtPlugin("com.typesafe.sbt" % "sbt-gzip" % "1.0.0-RC2")
// build.sbt
lazy val root = (project.in file(".")).enablePlugins(SbtWeb)

sbt-webの機能

  • アセットの標準的なディレクトリ構成
  • アセットパイプライン
  • JavaScriptの実行環境(sbt-js-engine)
  • アセットコンパイルの標準的なエラーレポート
  • インクリメンタルな実行機能

sbt-webのアセットのディレクトリ構成

Playとsbt-web系プラグインの依存関係

sbt-web系プラグインの分類

コード生成系プラグインの作り方

  • 今までsbtのResourceGeneratorとして作っていた人はsbt-webのファイル構成に合わせるだけで(たぶん)大丈夫
  • これから作る人で、JavaScriptで書かれたツールを使う場合はSbtJsTaskを使うのがおすすめ

SbtJsTask

  • JavaScriptを実行するTaskを簡単に(?)作ることができるプラグイン
  • NodeやRhinoなどのJavaScript実行環境を使ってScalaからJavaScriptを実行できる
  • sbt-webの標準的なエラーレポート機能やインクリメンタル実行機能を内部で使ってくれる
  • SbtJsTaskはアセットコンパイル以外にも使えるが、上記の理由から特にその用途がおすすめ

コード生成系プラグインのコード例

// SbtCoffeeScript.scala
override def projectSettings = Seq(
  bare := false,
  sourceMap := true
) ++ inTask(coffeescript)(
  SbtJsTask.jsTaskSpecificUnscopedSettings ++
    inConfig(Assets)(coffeeScriptUnscopedSettings) ++
    inConfig(TestAssets)(coffeeScriptUnscopedSettings) ++
    Seq(
      moduleName := "coffeescript",
      shellFile := getClass.getClassLoader.getResource("coffee.js"),
      taskMessage in Assets := "CoffeeScript compiling",
      taskMessage in TestAssets := "CoffeeScript test compiling"
    )
) ++ SbtJsTask.addJsSourceFileTasks(coffeescript) ++ Seq(
  coffeescript in Assets := (coffeescript in Assets).dependsOn(webModules in Assets).value,
  coffeescript in TestAssets := (coffeescript in TestAssets).dependsOn(webModules in TestAssets).value
)

コード生成系プラグインのコード例

アセットパイプライン系プラグインの作り方

  • TaskKeyをTask[Pipeline.Stage]で作る
  • ファイルの生成などを行い、mappingを修正して返す
  • 利用者に
    pipelineStages := Seq(rjs, digest, gzip)
    のように適用する順番を指定してもらう

アセットパイプライン系プラグインのコード例

// val gzip = TaskKey[Pipeline.Stage]("gzip-compress", "Add gzipped files to asset pipeline.")
// gzip := gzipFiles.value
def gzipFiles: Def.Initialize[Task[Pipeline.Stage]] = Def.task {
  mappings =>
    val targetDir = webTarget.value / gzip.key.label
    val include = (includeFilter in gzip).value
    val exclude = (excludeFilter in gzip).value
    val gzipMappings = for {
      (file, path) <- mappings if !file.isDirectory && include.accept(file) && !exclude.accept(file)
    } yield {
      val gzipPath = path + ".gz"
      val gzipFile = targetDir / gzipPath
      IO.gzip(file, gzipFile)
      (gzipFile, gzipPath)
    }
    mappings ++ gzipMappings
}

まとめ

  • sbt 0.13.5のAutoPluginで利用者もプラグイン開発者も便利に
  • sbt-web系プラグインは今が開発に参入するチャンス!
  • sbt-web系プラグインはPlayだけでなく他のフレームワークでも使うことができるよ
  • みんなでsbt-web系プラグインを作ろう!

<Thank You!>

Important contact information goes here.