Assets to CDN

121 views
Skip to first unread message

Neil Chaudhuri

unread,
Apr 16, 2015, 4:47:14 PM4/16/15
to play-fr...@googlegroups.com
There are a few CDN posts on here, but they are mostly dated. 

Ideally, I would like to make CDN publishing (and the ability to reference these assets in views) part of the sbt-web pipeline. Is there an existing plugin to do this? What are the current best practices for getting your static assets to a CDN?

Thanks.

Ben Developer

unread,
Apr 20, 2015, 8:34:06 PM4/20/15
to play-fr...@googlegroups.com
Neil,

The easiest way would be to use edge-caching. For example with Amazon AWS CloudFront, you setup a CDN distribution, then reference files via your code with the endpoint prefix they give you. When a request to the CDN comes in, it will request the file from Play then cache it, and serve the cached version for every subsequent request. In that way, it progressively "downloads" the assets and saves to the CDN for later requests.

Ben

Neil Chaudhuri

unread,
Apr 20, 2015, 8:56:50 PM4/20/15
to play-fr...@googlegroups.com
Ben,

While I appreciate the refresher on why CDNs are useful, that isn't what I asked. Please let me try to restate my question more clearly.

For the reasons you described, it is useful in production to push the jar of static assets to a CDN and have requests fetch the assets from there rather than from the web server. 

In development mode, everything should operate as it does now with the Assets controller doing its thing. Then during the build process, somehow the assets need to be compiled and assembled by sbt-web and pushed to the CDN. Or maybe not sbt-web, but something automated.

In production mode, another controller that is CDN-aware needs to be available to take requests and fetch the assets from the CDN. Then again, in order for this to be transparent to the views, I imagine there should actually be one controller that fetches from one place or another depending on mode.

Since this is a common need in any web application, I imagine most people in this group have solved the two key issues--automated CDN push and asset location resolution based on mode. So how do you guys do it with Play? Do you use Node packages for the push to CDN? How do you handle things at the controller and routes level?

Thanks.

Ben Developer

unread,
Apr 21, 2015, 12:21:05 PM4/21/15
to play-fr...@googlegroups.com
Neil, would be helpful to know which CDN you are trying to use. 

We use Cloudfront CDN in production. This means we do not have the ability to upload all of the assets at once. Rather, the CDN will cache and update them as requests to it come in (as I described in the earlier post). 

Here's the code we used, hopefully you can find it helpful.

1) RemoteAssets.scala in controllers folder:
package controllers


import play.api.Play
import play.api.Play.current
import play.api.mvc._


object RemoteAssets extends RemoteAssetsBuilder

class RemoteAssetsBuilder extends Controller {




 
/**
   * Gets the URL of the absolute URL of the asset in the CDN if the cdn.url config
   * is set. Otherwise it uses the relative url (from the current domain).
   */

 
def getUrl(file: String): String = {
   
Play.configuration.getString("cdn.url") match {
     
case Some(contentUrl) => contentUrl + routes.Assets.versioned(file).toString
     
case None => routes.Assets.versioned(file).toString
   
}
 
}


}

Then in your views, wherever you want to reference a file, you'd do something like this:

@RemoteAssets.getUrl("images/logo.png")

I assume you have two conf files; one for dev and one for prod. In application.conf do not define a cdn.url property. In production.conf, add something like:


And there you have it. Especially if you have asset fingerprinting enabled, Cloudfront will ask Play for the assets only once, then "remember" them later and will no longer request them from Play, but rather serve it from the CDN. It progressively downloads the assets. There's no way to upload an entire bundle of them at once.

Hope this helps.

Neil Chaudhuri

unread,
Apr 21, 2015, 12:25:58 PM4/21/15
to play-fr...@googlegroups.com
Ben, I am also using Cloudfront. In my previous experience with Rails, I was able to use the AssetSync gem to push assets to S3 as part of the Rails Asset Pipeline. That has formed the basis for my mental model for the kind of thing I'd like to accomplish with Play. Even though there is no sbt-web plugin to do the push, there are Node packages that theoretically can be integrated.

I'm going to study your code and see what I can do. Thanks so much for providing this.
Reply all
Reply to author
Forward
0 new messages