Monthly Archives: August 2015

Generate Gzipped Assets in Rails 4.2 +

Doesn’t Rails generate gzipped assets on running rake assets:precompile? It did so, until Rails 4.2. What changed?

Rails uses sprockets gem, for compiling and serving web assets. Before Sprockets 3 was introduced, rake assets:precompile generated .gz versions for all the assets.

This change, seems backward, for several reasons

  1. Gzipping should always be enabled for static assets. It’s super charges serving of static content.
  2. Assets should be gzip’ed beforehand as part of the build process, rather than letting the webserver do it on the fly, saving on CPU cycles.
  3. Also, Nginx has the ability to serve static .gz files directly, by using the gzip_static on; directive.

The reason for dropping this, was its incompatibility with Apache.

Since Sprockets 3 dropped this feature, it means Rails had to loose it too. The Rails team, plans to bring it back as an opt-in. Nevertheless, what does one do in the meantime?

Here are the options to generate Gzipped Assets with Rails

  1. depends on parallel gem to use multiple CPU cores, but can easily be simplified
  2. gzip assets with Capistrano
  3. write an assets:gzip rake task that plugs into assets:precompile (mentioned below)
namespace :assets do
  desc "Create .gz versions of assets"
  task :gzip => :environment do
    zip_types = /\.(?:css|html|js|otf|svg|txt|xml)$/

    public_assets = File.join(
      Rails.root,
      "public",
      Rails.application.config.assets.prefix)

    Dir["#{public_assets}/**/*"].each do |f|
      next unless f =~ zip_types

      mtime = File.mtime(f)
      gz_file = "#{f}.gz"
      next if File.exist?(gz_file) && File.mtime(gz_file) >= mtime

      File.open(gz_file, "wb") do |dest|
        gz = Zlib::GzipWriter.new(dest, Zlib::BEST_COMPRESSION)
        gz.mtime = mtime.to_i
        IO.copy_stream(open(f), gz)
        gz.close
      end

      File.utime(mtime, mtime, gz_file)
    end
  end

  # Hook into existing assets:precompile task
  Rake::Task["assets:precompile"].enhance do
    Rake::Task["assets:gzip"].invoke
  end
end
Minify Gzip

Minify vs gzip

While discussing some common optimisation techniques for the web, a discussion ensued on why are assets both minified and gzip’ed? Is it good for performance? Is there a benefit in minifying and then gzipping? Is it okay to gzip for HTTPS? What the heck, does HTTPS have to do with compression?

The average size of top 1,000 web pages is 1961kb today, compared to 1720kb in Aug 2014. This is a 14% growth, in just a year!  ~ HTTP Archive stats

Amount of data downloaded, by browsers to render a page has been steadily increasing. On the other hand, the performance requirements for end-users aren’t getting any better. Talking about web performance entails talking about 4 things

  1. Network transit time
  2. Response preparation (at server)
  3. Response parse (at client)
  4. Execution time (time taken to apply response on the page)

Given that, we can’t necessarily reduce data that gets generated, the only other way is to reduce its size for network transit (wire weight).

Minification is the practice of removing unnecessary characters (ex: comments, whitespace) from code

.. to reduce its size thereby improving load times. The browser can read and use it just like the original file. But since now, the wire weight is reduced, the page will load relatively faster. It also bundles various files into one, thus reducing the amount of requests to the web server.

Gzipping looks for repeating strings and replaces them with a pointer to the first occurrence

..The browser must decompress any compressed files before using them and this adds to the response parse time. We might have shaved off on some network transit time, but added to the response parse times.

Statistics to prove that gzip and minify is important

Normal Minified Gzipped Minified and gzipped
 JQUERY 2.1.3  241.59 KB 82.34 KB 71.68 KB 28.87 KB
 bootstrap-3.1.1.css  118 KB 98 KB  80 KB 17 KB

*gzip – gzip -6 file.js — the default compression level is 6 on a scale from 1 (fastest, but less compression) to 9 (slowest, but best compression).

A quick calculation gives us this.. On a 100 Mbps link,

Time to download Size
18.4319 ms 241.59 KB.
2.20261 ms 28.87 KB.

Needless to say, that this clearly tells us, to ensure static assets should always be minified and gzipped both.