Working with public assets
The public/ folder
By convention, public assets are stored in the
public folder of your application. This folder is organized as follows:
If you follow this structure it will be simpler to get started, but nothing stops you to modifying it once you understand how it works.
How are public assets packaged?
During the build process, the contents of the
public folder are processed and added to the application classpath. When you package your application, these files are packaged into the application JAR file (under the
The Assets controller
The controller is available in the default Play JAR as
controllers.Assets, and defines a single
at action with two parameters:
Assets.at(folder: String, file: String)
folder parameter must be fixed and defines the directory managed by the action. The
file parameter is usually dynamically extracted from the request path.
Here is the typical mapping of the
Assets controller in your
GET /assets/*file Assets.at("public", file)
Note that we define the
*file dynamic part that will match the
.* regular expression. So for example, if you send this request to the server:
The router will invoke the
Assets.at action with the following parameters:
This action will look-up the file and serve it, if it exists.
Note, if you define asset mappings outside “public,” you’ll need to tell
sbt about it, e.g. if you want:
GET /assets/*file Assets.at("public", file) GET /liabilities/*file Assets.at("foo", file)
you should add this to Build.scala:
playAssetsDirectories <+= baseDirectory / "foo"
Reverse routing for public assets
As for any controller mapped in the routes file, a reverse controller is created in
controllers.routes.Assets. You use this to reverse the URL needed to fetch a public resource. For example, from a template:
This will produce the following result:
Note that we don’t specify the first
folder parameter when we reverse the route. This is because our routes file defines a single mapping for the
Assets.at action, where the
folder parameter is fixed. So it doesn’t need to be specified explicitly.
However, if you define two mappings for the
Assets.at action, like this:
Then you will need to specify both parameters when using the reverse router:
Assets controller automatically manages ETag HTTP Headers. The ETag value is generated from the resource name and the file’s last modification date. (If the resource file is embedded into a file, the JAR file’s last modification date is used.)
When a web browser makes a request specifying this Etag, the server can respond with 304 NotModified.
If a resource with the same name but using a
.gz suffix is found, the
Assets controller will serve this one by adding the proper HTTP header:
Usually, using Etag is enough to have proper caching. However if you want to specify a custom
Cache-Control header for a particular resource, you can specify it in your
application.conf file. For example:
# Assets configuration # ~~~~~ "assets.cache./public/stylesheets/bootstrap.min.css"="max-age=3600"
By default play compiles all managed assets that are kept in the
app/assets folder. The compilation process will clean and recompile all managed assets regardless of the change. This is the safest strategy since tracking dependencies can be very tricky with front end technologies.
Note if you are dealing with a lot of managed assets this strategy can be very slow. For this reason there is a way to recompile only the change file and its supposed dependencies. You can turn on this experimental feature by adding the following to your settings:
incrementalAssetsCompilation := true
You will learn more about managed assets on the next few pages.
Next: Using CoffeeScript