herokugziprackdeflatecedar

How to enable gzip compression for static Rack sites on Heroku Cedar?


Following the Creating Static Sites in Ruby with Rack article, I get a static site on Heroku with a config.ru that looks like this:

use Rack::Static,
  :urls => ["/images", "/js", "/css"],
  :root => "public"

run lambda { |env|
  [
    200, 
    {
      'Content-Type'  => 'text/html', 
      'Cache-Control' => 'public, max-age=86400' 
    },
    File.open('public/index.html', File::RDONLY)
  ]
}

When I run YSlow over the result, it reported none of the files were gzipped. What do I do to compress both the assets and the public/index.html?


Solution

  • From my previous experience with Sprockets, Sinatra, and the Rack::Deflater, I was pretty sure I was just another use Rack::Deflater line away from what I wanted.

    I changed the config.ru to this:

    use Rack::Static,
      :urls => ["/images", "/js", "/css"],
      :root => "public"
    use Rack::Deflater
    
    run lambda # ...same as in the question
    

    and I was able to verify that responses were sent gzipped:

    $ curl -H 'Accept-Encoding: gzip' http://localhost:9292 | file -
    /dev/stdin: gzip compressed data
    

    but not for static assets under /css, /js, or /images:

    $ curl -H 'Accept-Encoding: gzip' http://localhost:9292/css/bootstrap.min.css | file -
    /dev/stdin: ASCII English text, with very long lines
    

    And that's when I realized this was a standard middleware stack—Rack::Static intercepts the call to static files and thus skips the following stack! That's why it worked for public/index.html but not for assets.

    The following config.ru worked (note that use Rack::Deflater now precedes use Rack::Static):

    use Rack::Deflater
    use Rack::Static, 
      :urls => ["/images", "/js", "/css"],
      :root => "public"
    
    run lambda { |env|
      [
        200, 
        {
          'Content-Type'  => 'text/html', 
          'Cache-Control' => 'public, max-age=86400' 
        },
        File.open('public/index.html', File::RDONLY)
      ]
    }
    

    Verified with:

    $ curl -H 'Accept-Encoding: gzip' http://localhost:9292/css/bootstrap.min.css | file -
    /dev/stdin: gzip compressed data, from Unix