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:
parent
6799606324
commit
c9b7bf4b59
18
middleman-more/features/gzip.feature
Normal file
18
middleman-more/features/gzip.feature
Normal 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"
|
||||||
|
|
1
middleman-more/fixtures/gzip-app/config.rb
Normal file
1
middleman-more/fixtures/gzip-app/config.rb
Normal file
|
@ -0,0 +1 @@
|
||||||
|
activate :gzip_assets
|
0
middleman-more/fixtures/gzip-app/source/index.html
Normal file
0
middleman-more/fixtures/gzip-app/source/index.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
function test_function() {}
|
|
@ -0,0 +1 @@
|
||||||
|
test_selector {}
|
|
@ -40,6 +40,9 @@ module Middleman
|
||||||
|
|
||||||
# MinifyJavascript uses the YUI compressor to shrink JS files
|
# MinifyJavascript uses the YUI compressor to shrink JS files
|
||||||
autoload :MinifyJavascript, "middleman-more/extensions/minify_javascript"
|
autoload :MinifyJavascript, "middleman-more/extensions/minify_javascript"
|
||||||
|
|
||||||
|
# GZIP assets during build
|
||||||
|
autoload :GzipAssets, "middleman-more/extensions/gzip_assets"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Setup renderers
|
# Setup renderers
|
||||||
|
@ -65,4 +68,6 @@ module Middleman
|
||||||
::Middleman::Extensions::MinifyJavascript }
|
::Middleman::Extensions::MinifyJavascript }
|
||||||
Extensions.register(:relative_assets) {
|
Extensions.register(:relative_assets) {
|
||||||
::Middleman::Extensions::RelativeAssets }
|
::Middleman::Extensions::RelativeAssets }
|
||||||
end
|
Extensions.register(:gzip_assets) {
|
||||||
|
::Middleman::Extensions::GzipAssets }
|
||||||
|
end
|
||||||
|
|
74
middleman-more/lib/middleman-more/extensions/gzip_assets.rb
Normal file
74
middleman-more/lib/middleman-more/extensions/gzip_assets.rb
Normal 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
|
Loading…
Reference in a new issue