Assets

Any web application would require a style sheet or some other resources such as images, scripts, and so in. In a non-Play application, we would refer to these by figuring out the relative location of the file. For example, suppose that our application has a webapp folder with index.html, where we need to add a homePage.css stylesheet, which is located at webapp/styles. Now, the reference in index.html would be something similar to the following:

<link rel="stylesheet" href="styles/homePage.css" />

Such relative paths can get very confusing and, at times, difficult to manage. In a Play application, the resources are placed in the public directory and can be accessed using a request. It is suggested that you split the public directory into three subdirectories for images, CSS style sheets, and JavaScript files for consistency, as shown in the following figure:

Assets

In addition to this, Play provides an asset controller by default to support requests, which can access resources (assets). In most Play applications, a route for assets is also available in the routes file, as shown here:

GET           /assets/*file        controllers.Assets.at(path="/public", file)

This route gives access to resources, such as style sheets, scripts, and so on. A file is expected to be the remainder of the path after /public, which is required to access it. For example, to get the homePage.css style sheet, we would send a GET request to /assets/stylesheets/homePage.css. The path preceded by /assets/ is considered to be the path for the file.

In views, we would need to use a routes helper. So, if we wish to add a style sheet in one of our views, we would refer to it as follows:

<link rel="stylesheet" href="@routes.Assets.at("stylesheets/homePage.css")" />

Similarly, we will refer to a JavaScript script as follows:

<script src="@routes.Assets.at("javascripts/slider.js")" type="text/javascript"></script>

It is also possible to specify a separate path for images, style sheets, or scripts so that the request paths are shorter, as shown here:

GET           /styles/*file        controllers.Assets.at(path="/public/styles", file)

GET           /images/*file        controllers.Assets.at(path="/public/images", file)

The Action at is defined as follows:

  def at(path: String, file: String, aggressiveCaching: Boolean = false): Action[AnyContent] = Action.async {
    implicit request =>

      import Implicits.trampoline
      val pendingResult: Future[Result] = for {
        Some(name) <- Future.successful(resourceNameAt(path, file))
        (assetInfo, gzipRequested) <- assetInfoForRequest(request, name)
      } yield {
        val stream = assetInfo.url(gzipRequested).openStream()
        Try(stream.available -> Enumerator.fromStream(stream)(Implicits.defaultExecutionContext)).map {
          case (length, resourceData) =>
            maybeNotModified(request, assetInfo, aggressiveCaching).getOrElse {
              cacheableResult(
                assetInfo,
                aggressiveCaching,
                result(file, length, assetInfo.mimeType, resourceData, gzipRequested, assetInfo.gzipUrl.isDefined)
              )
            }
        }.getOrElse(NotFound)
      }

      pendingResult.recover {
        case e: InvalidUriEncodingException =>
          Logger.debug(s"Invalid URI encoding for $file at $path", e)
          BadRequest
        case e: Throwable =>
          Logger.debug(s"Unforseen error for $file at $path", e)
          NotFound
      }
  }

Note

If a gzipped version of a file is available, the asset controller will serve that instead. A gzipped version refers to the version of the file that was obtained by compressing the file using gzip. It adds the .gz extension to the filename.

As well as the resource, AssetController adds the etag header.

The etag acronym is used for an entity tag. This is a unique identifier for the resource being requested, and is generally a hash of the resource or of its last modified timestamp.

Client-side libraries

Views in most applications rely on third-party libraries. In Play, we could define dependencies located in such libraries using webJars and npm.

Play extracts the assets from the WebJar dependencies as well as from npm packages into the lib directory within the public assets. We can refer to these when defining an asset with a dependency on the files present there. For example, if our view depends on d3.js, then we use the following:

<script src="@routes.Assets.at("lib/d3/d3.v3.min.js")" charset="utf-8"></script>

Note

WebJars are JARs of libraries used for the client-side development of a web application.

npm is an acronym for node packaged modules. It is the package manager for Node.js. It allows developers to install registered modules through the command line.

To use a WebJar, we would need to define our project's dependency on it just as in any other module, as shown here:

libraryDependencies+="org.webjars" % "d3js" % "3.4.6-1"  

To include npm packages, we would need to place the package.json file in a project root. The package.json file would be similar to this:

{
  "name": "myApp",
  "version": "1.0.0",
  "dependencies": {
  },
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-concat": "~0.1.3",
    "grunt-contrib-cssmin": "~0.5.0",
    "grunt-contrib-clean": "~0.4.0",
    "grunt-contrib-less": "~0.7.0"
  },
  "engines": {
    "node": ">=0.8.0"
  }
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
52.15.42.128