Extension that will pre-Gzip JS and CSS files. Gzipped assets can be served directly by Apache or Nginx with the proper configuration, and pre-zipping means that we can use a more agressive compression level at no CPU cost per request.

This commit is contained in:
Ben Hollis 2012-02-10 20:09:39 -08:00
parent 6799606324
commit c9b7bf4b59
7 changed files with 101 additions and 1 deletions

View file

@ -0,0 +1,18 @@
Feature: GZIP assets during build
Scenario: Built assets should be gzipped
Given a successfully built app at "gzip-app"
Then the following files should exist:
| build/javascripts/test.js.gz |
| build/stylesheets/test.css.gz |
| build/index.html |
When I run `file build/javascripts/test.js.gz`
Then the output should contain "gzip"
Scenario: Preview server doesn't change
Given the Server is running at "gzip-app"
When I go to "/javascripts/test.js"
Then I should see "test_function"
When I go to "/stylesheets/test.css"
Then I should see "test_selector"

View file

@ -0,0 +1 @@
activate :gzip_assets

View file

@ -0,0 +1 @@
function test_function() {}

View file

@ -0,0 +1 @@
test_selector {}

View file

@ -40,6 +40,9 @@ module Middleman
# MinifyJavascript uses the YUI compressor to shrink JS files
autoload :MinifyJavascript, "middleman-more/extensions/minify_javascript"
# GZIP assets during build
autoload :GzipAssets, "middleman-more/extensions/gzip_assets"
end
# Setup renderers
@ -65,4 +68,6 @@ module Middleman
::Middleman::Extensions::MinifyJavascript }
Extensions.register(:relative_assets) {
::Middleman::Extensions::RelativeAssets }
Extensions.register(:gzip_assets) {
::Middleman::Extensions::GzipAssets }
end

View file

@ -0,0 +1,74 @@
require 'zlib'
require 'stringio'
module Middleman::Extensions
# This extension Gzips assets when building.
# Gzipped assets can be served directly by Apache or
# Nginx with the proper configuration, and pre-zipping means that we
# can use a more agressive compression level at no CPU cost per request.
module GzipAssets
class << self
def registered(app)
return unless app.inst.build?
app.after_configuration do
# Register a reroute transform that adds .gz to asset paths
sitemap.reroute do |destination, page|
if %w(.js .css).include? page.ext
destination + '.gz'
else
destination
end
end
use GzipRack
end
end
alias :included :registered
end
# Rack middleware to GZip asset files
class GzipRack
# Init
# @param [Class] app
# @param [Hash] options
def initialize(app, options={})
@app = app
end
# Rack interface
# @param [Rack::Environmemt] env
# @return [Array]
def call(env)
status, headers, response = @app.call(env)
if env["PATH_INFO"].match(/\.(js|css).gz$/)
contents = case(response)
when String
response
when Array
response.join
when Rack::Response
response.body.join
when Rack::File
File.read(response.path)
end
gzipped = ""
StringIO.open(gzipped) do |s|
gz = Zlib::GzipWriter.new(s, Zlib::BEST_COMPRESSION)
gz.write contents
gz.close
end
headers["Content-Length"] = ::Rack::Utils.bytesize(gzipped).to_s
response = [gzipped]
end
[status, headers, response]
end
end
end
end