Ruby on Rails: Minify HTML, CSS, & JS, and compress with gzip

Update (2015-08-21): Do not use this. You will hate me for saying this, as this page is one of my most popular on the site, but after using my code on this page with Rails for quite a while, I came back on my own decision to use it. I knew compressing pages on every request would add some overhead, but I didn’t think it would be that significant – and it is, a lot.

While this would work with preprocessors like Middleman, which compresses all the files only once, doing so with an app generating pages on every request will slow down the application. You may install performance monitoring software like New Relic then toggle the compression to see the difference.

When optimising Web sites or apps for speed, any little bit helps. One of the easiest things to do is to “minify” all source files, removing all unncessary blank spaces, line breaks, and comments, and then compress them on the fly using gzip.

The simple initializer file below can be dropped in any Ruby on Rails app running via Rack (which includes Heroku) to minify all HTML, CSS, and JavaScript files, as well as compressing them with gzip for HTTP connections before sending them to the browser:

# config/initializers/compression.rb

Rails.application.configure do
  # Use environment names or environment variables:
  # break unless Rails.env.production? 
  break unless ENV['ENABLE_COMPRESSION'] == '1'
  
  # Strip all comments from JavaScript files, even copyright notices.
  # By doing so, you are legally required to acknowledge
  # the use of the software somewhere in your Web site or app:
  uglifier = Uglifier.new output: { comments: :none }

  # To keep all comments instead or only keep copyright notices (the default):
  # uglifier = Uglifier.new output: { comments: :all }
  # uglifier = Uglifier.new output: { comments: :copyright }

  config.assets.compile = true
  config.assets.debug = false

  config.assets.js_compressor = uglifier
  config.assets.css_compressor = :sass

  config.middleware.use Rack::Deflater
  config.middleware.insert_before ActionDispatch::Static, Rack::Deflater

  config.middleware.use HtmlCompressor::Rack,
    compress_css: true,
    compress_javascript: true,
    css_compressor: Sass,
    enabled: true,
    javascript_compressor: uglifier,
    preserve_line_breaks: false,
    remove_comments: true,
    remove_form_attributes: false,
    remove_http_protocol: false,
    remove_https_protocol: false,
    remove_input_attributes: true,
    remove_intertag_spaces: false,
    remove_javascript_protocol: true,
    remove_link_attributes: true,
    remove_multi_spaces: true,
    remove_quotes: true,
    remove_script_attributes: true,
    remove_style_attributes: true,
    simple_boolean_attributes: true,
    simple_doctype: false
end

Also available as a gist on GitHub.

Notes

  • The code above uses environment variables by default, which I often use to enable or disable features instead of going by the environment name.
  • Despite the point above, no matter how hard you try, Rails will only allow Sass to compress the output on production.
  • As indicated in the code comments, enabling comments: :none for the JavaScript Uglifier will strip absolutely all comments, even copyright notices. When doing so, you are legally required to acknowledge the use of the software in a note somewhere on your site or app. Alternatives are to strip comments except legal notes with comments: :copyright or keep all comments with comments: :all.
  • There seems to be no way for Sass to strip out copyright notices, or any such comments usually beginning with /*!.

Leave a Reply