Skip navigation

Rails applications have a snazzy feature that, when caching is turned on, will combine Javascript and CSS files you specify into files named all.js and all.css respectively. This greatly reduces the number of files that need to be downloaded by the browser to render the web page. These aggregate files are not generated until the first request is made for the files.

 

As Rob blogged in May, Trainer 2 is now using Unicorn for no-downtime deployments. This is great, however it means that our all.js and all.css files will not be generated until the first request is made after the new release - and this means the first request after a new release will incur the extra processing time required to build those files, which is less than ideal.

 

So what are our options?

  • We can just accept that that is the way it is going to work, and hope the extra time incurred is minimal. This will obviously work, but why not try to address the issue before it becomes a problem?
  • We can build all.js and all.css ourselves in the deployment script. This will get us what we want - the files will be built before the first request to the server is made, however it's not very flexible. We would need to update the deployment script every time we wanted to include a new file in all.js or all.css.
  • In the deployment script, we can simulate a request to the server, which will cause all.js and all.css to be built. This too will result in the files being built before the first user request is made to the server, and since the server that is building the files, it will generate them from the files specified in the application - no further configuration is required.

So how can we create a recipe in our Capistrano deployment file that will open a connection to the server, but we also don't want to hard code any URLs so that we don't have to update the deployment script if we need to change the URL for the application?

 

We can create a rake task that will open a connection and issue a get request to the root of the current application:

namespace :assets do

  desc 'Generate all.css and all.js'

  task :generate_cached_assets => :environment do

    session=ActionDispatch::Integration::Session.new(Rails.application)

    session.get '/'

  end

end

 

 

Then we can access that rake task from our deployment script:

desc "Requests the homepage, thus forcing the cached JS and CSS to build"

task :build_cached_js_and_css, :roles => :web do

  run "rake -f #{release_path}/Rakefile assets:generate_cached_assets RAILS_ENV=#{rails_env}"

end

 

 

We'll call that task in the deployment after the CSS files are generated:

#after updating CSS files, build all.css and all.js

after 'deploy:sass:update', 'deploy:build_cached_js_and_css'

 

 

Voilà! Since the request to build all.js and all.css is made during the deployment process, the files will have been built before Unicorn starts serving requests.

1,720 Views 0 Comments Permalink