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
- Gzipping should always be enabled for static assets. It’s super charges serving of static content.
- 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.
- Also, Nginx has the ability to serve static
.gz
files directly, by using thegzip_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
- depends on
parallel
gem to use multiple CPU cores, but can easily be simplified - gzip assets with Capistrano
- 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