The new activator command and the old play command are both wrappers around sbt. If you prefer, you can use the sbt command directly. However, if you use sbt you will miss out on several Activator features, such as templates (activator new) and the web user interface (activator ui). Both sbt and Activator support all the usual console commands such as test and run.

Play is distributed as an Activator distribution that contains all Play’s dependencies. You can download this distribution from the Play download page.

If you prefer, you can also download a minimal (1MB) version of Activator from the Activator site. Look for the “mini” distribution on the download page. The minimal version of Activator will only download dependencies when they’re needed.

Since Activator is a wrapper around sbt, you can also download and use sbt directly, if you prefer.

Auto plugins permit sbt plugins to be declared in the project folder (typically the plugins.sbt) as before. What has changed though is that plugins may now declare their requirements of other plugins and what triggers their enablement for a given build. Before auto plugins, plugins added to the build were always available; now plugins are enabled selectively for given modules.

What this means for you is that declaring addSbtPlugin may not be sufficient for plugins that now utilize to the auto plugin functionality. This is a good thing. You may now be selective as to which modules of your project should have which plugins e.g.:

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

The above example shows SbtWeb being added to the root project of a build. In the case of SbtWeb there are other plugins that become enabled if it is e.g. if you also had added the sbt-less-plugin via addSbtPlugin then it will become enabled just because SbtWeb has been enabled. SbtWeb is thus a “root” plugin for that category of plugins.

Play itself is now added using the auto plugin mechanism. The mechanism used in Play 2.2 where playJavaSettings and playScalaSettings were used has been removed. You now use one of the following instead:

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

or

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

If you were previously using play.Project, for example a Scala project:

The largest new feature for Play 2.3 is the introduction of sbt-web. In summary sbt-web allows Html, CSS and JavaScript functionality to be factored out of Play’s core into a family of pure sbt plugins. There are two major advantages to you:

Play is less opinionated on the Html, CSS and JavaScript; and

sbt-web can have its own community and thrive in parallel to Play’s.

There are other advantages including the fact that sbt-web plugins are able to run within the JVM via Trireme, or natively using Node.js. Note that sbt-web is a development environment and does not participate in the execution of a Play application. Trireme is used by default, but if you have Node.js installed and want blistering performance for your builds then you can provide a system property via sbt’s SBT_OPTS environment variable. For example:

export SBT_OPTS="$SBT_OPTS -Dsbt.jse.engineType=Node"

A feature of sbt-web is that it is not concerned whether you use “javascripts” or “stylesheets” as your folder names. Any files with the appropriate filename extensions are filtered from within the app/assets folder.

A nuance with sbt-web is that all assets are served from the public folder. Therefore if you previously had assets reside outside of the public folder i.e. you used the playAssetsDirectories setting as per the following example:

playAssetsDirectories <+= baseDirectory / "foo"

…then you should now use the following:

unmanagedResourceDirectories in Assets += baseDirectory.value / "foo"

…however note that the files there will be aggregated into the target public folder. This means that a file at “public/a.js” will be overwritten with the file at “foo/a.js”. Alternatively use sub folders off your project’s public folder in order to namespace them.

The following lists all sbt-web related components and their versions at the time of releasing Play 2.3.

WebJars now play an important role in the provision of assets to a Play application. For example you can declare that you will be using the popular Bootstrap library simply by adding the following dependency in your build file:

libraryDependencies += "org.webjars" % "bootstrap" % "3.0.0"

WebJars are automatically extracted into a lib folder relative to your public assets for convenience. For example if you declared a dependency on RequireJs then you can reference it from a view using a line like:

Note the lib/requirejs/require.js path. The lib folder denotes the extract WebJar assets, the requirejs folder corresponds to the WebJar artifactId, and the require.js refers to the required asset at the root of the WebJar.

npm can be used as well as WebJars by declaring a package.json file in the root of your project. Assets from npm packages are extracted into the same lib folder as WebJars so that, from a code perspective, there is no concern whether the asset is sourced from a WebJar or from an npm package.

From your perspective we aim to offer feature parity with previous releases of Play. While things have changed significantly under the hood the transition for you should be minor. The remainder of this section looks at each part of Play that has been replaced with sbt-web and describes what should be changed.

Unlike Play 2.2, the sbt-less plugin allows any user to download the original LESS source file and generated source maps. It allows easier debugging in modern web browsers. This feature is enabled even in production mode.

The Closure Compiler has been replaced. Its two important functions of validating JavaScript and minifying it have been factored out into JSHint and UglifyJS 2 respectively.

To use JSHint you must declare it, typically in your plugins.sbt file:

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

Options can be specified in accordance with the JSHint website and they share the same set of defaults. To set an option you can provide a .jshintrc file within your project’s base directory. If there is no such file then a .jshintrc file will be searched for in your home directory. This behaviour can be overridden by using a JshintKeys.config setting for the plugin.JshintKeys.config is used to specify the location of a configuration file.

The RequireJS Optimizer (rjs) has been entirely replaced with one that should be a great deal easier to use. The new rjs is part of sbt-web’s asset pipeline functionality. Unlike its predecessor which was invoked on every build, the new one is invoked only when producing a distribution via Play’s stage or dist tasks.

To use rjs you must declare it, typically in your plugins.sbt file:

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

To add the plugin to the asset pipeline you can declare it as follows:

pipelineStages := Seq(rjs)

We also recommend that sbt-web’s sbt-digest and sbt-gzip plugins are included in the pipeline. sbt-digest will provide Play’s asset controller with the ability to fingerprint asset names for far-future caching. sbt-gzip produces a gzip of your assets that the asset controller will favor when requested. Your plugins.sbt file for this configuration will then look like:

The order of stages is significant. You first want to optimize the files, produce digests of them and then produce gzip versions of all resultant assets.

The options for RequireJs optimization have changed entirely. The plugin’s options are:

Option

Description

appBuildProfile

The project build profile contents.

appDir

The top level directory that contains your app js files. In effect, this is the source folder that rjs reads from.

baseUrl

The dir relative to the assets or public folder where js files are housed. Will default to “js”, “javascripts” or “.” with the latter if the other two cannot be found.

buildProfile

Build profile key -> value settings in addition to the defaults supplied by appBuildProfile. Any settings in here will also replace any defaults.

dir

By default, all modules are located relative to this path. In effect this is the target directory for rjs.

generateSourceMaps

By default, source maps are generated.

mainConfig

By default, ‘main’ is used as the module for configuration.

mainConfigFile

The full path to the above.

mainModule

By default, ‘main’ is used as the module.

modules

The json array of modules.

optimize

The name of the optimizer, defaults to uglify2.

paths

RequireJS path mappings of module ids to a tuple of the build path and production path. By default all WebJar libraries are made available from a CDN and their mappings can be found here (unless the cdn is set to None).

Due to Play now using Activator as a launcher, it now uses the default ivy cache and local repository. This means anything previously published to your Play ivy cache that you depend on will need to be published to the local ivy repository in the .ivy2 folder in your home directory.

The following deprecated types and helpers from Play 2.1 have been removed:

play.api.mvc.PlainResult

play.api.mvc.ChunkedResult

play.api.mvc.AsyncResult

play.api.mvc.Async

If you have code that is still using these, please see the Play 2.2 Migration Guide to learn how to migrate to the new results structure.

As planned back in 2.2, 2.3 has renamed play.api.mvc.SimpleResult to play.api.mvc.Result (replacing the existing Result trait). A type alias has been introduced to facilitate migration, so your Play 2.2 code should be source compatible with Play 2.3, however we will eventually remove this type alias so we have deprecated it, and recommend switching to Result.

The following deprecated types and helpers from Play 2.1 have been removed:

play.mvc.Results.async

play.mvc.Results.AsyncResult

If you have code that is still using these, please see the Play 2.2 Migration Guide to learn how to migrate to the new results structure.

As planned back in 2.2, 2.3 has renamed play.mvc.SimpleResult to play.mvc.Result. This should be transparent to most Java code. The most prominent places where this will impact is in the Global.java error callbacks, and in custom actions.

The template content types have moved to the twirl package. If the play.mvc.Content type is referenced then it needs to be updated to play.twirl.api.Content. For example, the following code in a Play Java project:

In addition, usage of the WS client now requires a Play application in scope. Typically this is achieved by adding:

import play.api.Play.current

The WS API has changed slightly, and WS.client now returns an instance of WSClient rather than the underlying AsyncHttpClient object. You can get to the AsyncHttpClient by calling WS.client.underlying.

For improved type safety, type of query parameter must be visible, so that it can be properly converted. Now using Any as parameter value, explicitly or due to erasure, leads to compilation error No implicit view available from Any => anorm.ParameterValue.

The in-built Twitter Bootstrap field constructor has been deprecated, and will be removed in a future version of Play.

There are a few reasons for this, one is that we have found that Bootstrap changes too drastically between versions and too frequently, such that any in-built support provided by Play quickly becomes stale and incompatible with the current Bootstrap version.

Another reason is that the current Bootstrap requirements for CSS classes can’t be implemented with Play’s field constructor alone, a custom input template is also required.

Our view going forward is that if this is a feature that is valuable to the community, a third party module can be created which provides a separate set of Bootstrap form helper templates, specific to given Bootstrap versions, allowing a much better user experience than can currently be provided.

The session timeout configuration item, session.maxAge, used to be an integer, defined to be in seconds. Now it’s a duration, so can be specified with values like 1h or 30m. Unfortunately, the default unit if specified with no time unit is milliseconds, which means a config value of 3600 was previously treated as one hour, but is now treated as 3.6 seconds. You will need to update your configuration to add a time unit.

The Java WithApplication, WithServer and WithBrowser JUnit test superclasses have been modified to define an @Before annotated method. This means, previously where you had to explicitly start a fake application by defining:

@Before
public void setUp() {
start();
}

Now you don’t need to. If you need to provide a custom fake application, you can do so by overriding the provideFakeApplication method:

The Scala Controller provides implicit Session, Flash and Lang parameters, that take an implicit RequestHeader. These exist for convenience, so a template for example can take an implicit argument and they will be automatically provided in the controller. The name of these was changed to avoid conflicts where these parameter names might be shadowed by application local variables with the same name. session became request2session, flash became request2flash, lang became request2lang. Any code that invoked these explicitly consequently will break.

It is not recommended that you invoke these implicit methods explicitly, the session, flash and lang parameters are all available on the RequestHeader, and using the RequestHeader properties makes it much clearer where they come from when reading the code. It is recommended that if you have code that uses the old methods, that you modify it to access the corresponding properties on RequestHeader directly.