Why use a CDN?
In addition, most browsers have a setting that limits the number of connections (usually 2) that it will open in parallel to a given domain. By using a CDN, you can increase the number of parallel requests because these assets are not served up by your application’s domain.
It’s also a common practice to use dns to “alter” the domain so that you can maximize this parallelization.
Using the asset sync gem
Following the instructions on Heroku’s Devcenter article I
decided to use the
asset_sync gem. This gem will upload your compiled assets to your preferred CDN (any file storage server that
fog supports). In my case, I wanted to use S3.
The first step is adding this gem to your
1 2 3 4
It’s important to put this in your asset group, as your running app doesn’t need to load this into memory.
Then you need to configure the gem. I found Heroku’s instructions to be lacking here, as I had to dig into
asset_sync github page to make this work.
Add a file called
config/initializers/asset_sync.rb to your app:
1 2 3 4 5 6 7 8 9 10 11 12 13
That last config line is important. When you deploy to Heroku, your app’s assets will get precompiled. But because Heroku doesn’t initialize your app on precompile, none of your settings will be available. Instead we’ll have to run the precompile again, manually, to get AssetSync to kick in.
Setting up the configuration with Heroku San
Since I like to have multiple environments, I use
heroku_san to manage them, including
the environment variables.
config/heroku.yml, set up the following for each environment:
1 2 3 4
Configuring Your Rails app to use S3 as an Asset Host
staging.rb if you have one), make sure to add the
following line to allow Rails to generate the appropriate links for your assets:
1 2 3 4
This will allow your app to serve up the URLs using SSL if the request is coming via SSL. Doing this can avoid warnings in the browser that your app contains secure and unsecure content.
Testing it all out
If all of this is configured correctly, you can test it out by doing a push…
You’ll see the asset precompile going on in the logs, and likely an error related to AssetSync. This is fine (and in fact, this tripped me up at first). Once the deploy has completed, you’ll have to run this command to upload your assets:
Doing this, you should see something like the following output:
1 2 3 4 5 6
Set up Heroku San to do this on every deploy
I’d likely forget to run this command every once in a while, so I set up Heroku San to run this command after every deploy.
To do this, add a new rake task in your app (
1 2 3 4 5 6
Now when you run your deploy via
rake production deploy this will happen automatically.
So what’s the net result?
Doing this alleviated nearly 30 secondary requests to my application for each page load. That alone is pretty huge. Also, S3 is much faster at serving these assets than nginx is (at least via a Heroku app on 1 dyno).
I tested this before and after by clearing the cache and doing a fresh page load. Using the Chrome Inspector, I looked at the time to load the page and all assets. Here are my findings:
|Before (serving assets with no CDN)||3.27 seconds|
|After (using S3 as a CDN)||1.07 seconds|
That’s a huge gain for a minor change in your application & deployment process.