§SBT Cookbook
§Hooking into Play’s dev mode
When Play runs in dev mode, that is, when using sbt run
, it’s often useful to hook into this to start up additional processes that are required for development. This can be done by defining a PlayRunHook
, which is a trait with the following methods:
beforeStarted(): Unit
- called before the play application is started, but after all “before run” tasks have been completed.afterStarted(): Unit
- called after the play application has been started.afterStopped(): Unit
- called after the play process has been stopped.
Now let’s say you want to build a Web application with grunt
before the application is started. First, you need to create a Scala object in the project/
directory to extend PlayRunHook
. Let’s name it Grunt.scala
:
import play.sbt.PlayRunHook
import sbt._
import scala.sys.process.Process
object Grunt {
def apply(base: File): PlayRunHook = {
object GruntProcess extends PlayRunHook {
override def beforeStarted(): Unit = {
Process("grunt dist", base).run
}
}
GruntProcess
}
}
Now you can register this hook in build.sbt
:
PlayKeys.playRunHooks += Grunt(baseDirectory.value)
This will execute the grunt dist
command in baseDirectory
before the application is started whenever you run sbt run
.
Now we want to modify our run hook to execute the grunt watch
command to observe changes and rebuild the Web application when they happen, so we’ll modify the Grunt.scala
file we created before:
import play.sbt.PlayRunHook
import sbt._
import java.net.InetSocketAddress
import scala.sys.process.Process
object Grunt {
def apply(base: File): PlayRunHook = {
object GruntProcess extends PlayRunHook {
var watchProcess: Option[Process] = None
override def beforeStarted(): Unit = {
Process("grunt dist", base).run
}
override def afterStarted(): Unit = {
watchProcess = Some(Process("grunt watch", base).run)
}
override def afterStopped(): Unit = {
watchProcess.map(p => p.destroy())
watchProcess = None
}
}
GruntProcess
}
}
Now when the application is started using sbt run
, grunt watch
will be executed to rerun the grunt build whenever files change.
§Add compiler options
For example, you may want to add the feature flag to have details on feature warnings:
[info] Compiling 1 Scala source to ~/target/scala-2.10/classes...
[warn] there were 1 feature warnings; re-run with -feature for details
Simply add -feature
to the scalacOptions
attribute:
scalacOptions += "-feature"
§Add additional asset directory
For example you can add the pictures
folder to be included as an additional asset directory:
unmanagedResourceDirectories in Assets += baseDirectory.value / "pictures"
This will allow you to use routes.Assets.at
with this folder.
§Configure externalized resources
Since Play 2.4 the content of the conf
directory is added to the classpath by default.
When packaging a Play application for production that conf
folder (or it’s content) can exist in two places:
Either the conf
folder will not be packaged into a jar
file (together with the rest of the application) but instead stays outside that jar
file on the file system. Therefore the content of that conf
folder (e.g. application.conf
) can be edited and by restarting the application any changes will be picked up immediately - there is no need to repackage and redeploy an application. This is the default.
Or Play can be configured to always put the content of the conf
folder inside the application jar
file. This can be done by setting
PlayKeys.externalizeResources := false
in build.sbt
. Sometimes this behaviour is needed for cases where a library requires (some) resources of the conf
folder and the application class files to live inside the same jar
file in order to work correctly.
Since Play 2.7 another configuration key exists that allows you to exclude specific resources so they won’t be externalized, even though when PlayKeys.externalizeResources := true
:
PlayKeys.externalizeResourcesExcludes += baseDirectory.value / "conf" / "somefolder" / "somefile.xml"
Thanks to this configuration key you don’t have to put all the files of the conf
folder into the jar
file anymore when that is needed only for some specific files.
§Disable documentation
To speed up compilation you can disable documentation generation:
sources in (Compile, doc) := Seq.empty
publishArtifact in (Compile, packageDoc) := false
The first line will disable documentation generation and the second one will avoid to publish the documentation artifact.
§Configure ivy logging level
By default ivyLoggingLevel
is set on UpdateLogging.DownloadOnly
. You can change this value with:
UpdateLogging.Quiet
only displays errorsUpdateLogging.FULL
logs the most
For example if you want to only display errors:
ivyLoggingLevel := UpdateLogging.Quiet
§Fork and parallel execution in test
By default parallel execution is disabled and fork is enabled. You can change this behavior by setting parallelExecution in Test
and/or fork in Test
:
parallelExecution in Test := true
fork in Test := false
Next: Debugging your build