diff --git a/middleman-core/lib/middleman-core/step_definitions/server_steps.rb b/middleman-core/lib/middleman-core/step_definitions/server_steps.rb index 7a75cb20..141d9dae 100644 --- a/middleman-core/lib/middleman-core/step_definitions/server_steps.rb +++ b/middleman-core/lib/middleman-core/step_definitions/server_steps.rb @@ -68,10 +68,14 @@ Then /^I should see '([^\']*)'$/ do |expected| @browser.last_response.body.should include(expected) end +Then /^I should see:$/ do |expected| + @browser.last_response.body.should include(expected) +end + Then /^I should not see "([^\"]*)"$/ do |expected| @browser.last_response.body.should_not include(expected) end Then /^I should see "([^\"]*)" lines$/ do |lines| @browser.last_response.body.chomp.split($/).length.should == lines.to_i -end \ No newline at end of file +end diff --git a/middleman-core/lib/middleman-core/templates.rb b/middleman-core/lib/middleman-core/templates.rb index 95d0f461..365a76bc 100644 --- a/middleman-core/lib/middleman-core/templates.rb +++ b/middleman-core/lib/middleman-core/templates.rb @@ -59,8 +59,9 @@ module Middleman::Templates return unless options[:bundler] template "shared/Gemfile.tt", File.join(location, "Gemfile") - say_status :run, "bundle install" - print `cd #{location} && "#{Gem.ruby}" -rubygems "#{Gem.bin_path('bundler', 'bundle')}" install` + inside(location) do + run('bundle install', :capture => true) + end end end end diff --git a/middleman-more/features/minify_css.feature b/middleman-more/features/minify_css.feature index 80b3f8ce..cbebdf37 100644 --- a/middleman-more/features/minify_css.feature +++ b/middleman-more/features/minify_css.feature @@ -1,6 +1,9 @@ Feature: Minify CSS In order reduce bytes sent to client and appease YSlow + Background: + Given current environment is "build" + Scenario: Rendering external css with the feature disabled Given "minify_css" feature is "disabled" And the Server is running at "minify-css-app" @@ -14,8 +17,51 @@ Feature: Minify CSS When I go to "/stylesheets/site.css" Then I should see "1" lines And I should see "only screen and (device-width" + When I go to "/more-css/site.css" + Then I should see "1" lines Scenario: Rendering external css with passthrough compressor Given the Server is running at "passthrough-app" When I go to "/stylesheets/site.css" - Then I should see "55" lines \ No newline at end of file + Then I should see "55" lines + + Scenario: Rendering inline css with the feature disabled + Given "minify_css" feature is "disabled" + And the Server is running at "minify-css-app" + When I go to "/inline-css.html" + Then I should see: + """ + + """ + + Scenario: Rendering inline css with a passthrough minifier + Given the Server is running at "passthrough-app" + When I go to "/inline-css.html" + Then I should see: + """ + + """ + + Scenario: Rendering inline css with the feature enabled + Given "minify_css" feature is "enabled" + And the Server is running at "minify-css-app" + When I go to "/inline-css.html" + Then I should see: + """ + + """ \ No newline at end of file diff --git a/middleman-more/features/minify_javascript.feature b/middleman-more/features/minify_javascript.feature index bcf9cd3a..251fb90c 100644 --- a/middleman-more/features/minify_javascript.feature +++ b/middleman-more/features/minify_javascript.feature @@ -8,24 +8,106 @@ Feature: Minify Javascript Given "minify_javascript" feature is "disabled" And the Server is running at "minify-js-app" When I go to "/inline-js.html" - Then I should see "10" lines + Then I should see: + """ + + + + + """ Scenario: Rendering inline js with a passthrough minifier Given the Server is running at "passthrough-app" When I go to "/inline-js.html" - Then I should see "11" lines + Then I should see: + """ + + + + + """ Scenario: Rendering inline js with the feature enabled Given "minify_javascript" feature is "enabled" And the Server is running at "minify-js-app" When I go to "/inline-js.html" - Then I should see "5" lines + Then I should see: + """ + + + + + """ Scenario: Rendering external js with the feature enabled Given "minify_javascript" feature is "enabled" And the Server is running at "minify-js-app" When I go to "/javascripts/js_test.js" Then I should see "1" lines + When I go to "/more-js/other.js" + Then I should see "1" lines Scenario: Rendering external js with a passthrough minifier And the Server is running at "passthrough-app" @@ -36,7 +118,7 @@ Feature: Minify Javascript Given "minify_javascript" feature is "enabled" And the Server is running at "minify-js-app" When I go to "/inline-coffeescript.html" - Then I should see "5" lines + Then I should see "6" lines Scenario: Rendering external js (coffeescript) with the feature enabled Given "minify_javascript" feature is "enabled" @@ -47,9 +129,10 @@ Feature: Minify Javascript Scenario: Rendering inline js (coffeescript) with a passthrough minifier Given the Server is running at "passthrough-app" When I go to "/inline-coffeescript.html" - Then I should see "17" lines + Then I should see "16" lines Scenario: Rendering external js (coffeescript) with a passthrough minifier And the Server is running at "passthrough-app" When I go to "/javascripts/coffee_test.js" - Then I should see "11" lines \ No newline at end of file + Then I should see "11" lines + \ No newline at end of file diff --git a/middleman-more/fixtures/minify-css-app/source/inline-css.html.haml b/middleman-more/fixtures/minify-css-app/source/inline-css.html.haml new file mode 100644 index 00000000..6df15054 --- /dev/null +++ b/middleman-more/fixtures/minify-css-app/source/inline-css.html.haml @@ -0,0 +1,5 @@ +:css + body { + test: style; + good: deal; + } diff --git a/middleman-more/fixtures/minify-css-app/source/more-css/site.css b/middleman-more/fixtures/minify-css-app/source/more-css/site.css new file mode 100644 index 00000000..b66215ff --- /dev/null +++ b/middleman-more/fixtures/minify-css-app/source/more-css/site.css @@ -0,0 +1,3 @@ +body { + display: block; +} diff --git a/middleman-more/fixtures/minify-js-app/config.rb b/middleman-more/fixtures/minify-js-app/config.rb index e80254e0..5683946a 100644 --- a/middleman-more/fixtures/minify-js-app/config.rb +++ b/middleman-more/fixtures/minify-js-app/config.rb @@ -1 +1 @@ -require "coffee-filter" \ No newline at end of file +require "coffee-filter" diff --git a/middleman-more/fixtures/minify-js-app/source/inline-js.html.haml b/middleman-more/fixtures/minify-js-app/source/inline-js.html.haml index 06197239..7b383e47 100755 --- a/middleman-more/fixtures/minify-js-app/source/inline-js.html.haml +++ b/middleman-more/fixtures/minify-js-app/source/inline-js.html.haml @@ -4,4 +4,25 @@ should(); all.be(); on = { one: line }; - })(); \ No newline at end of file + })(); + +%script + :plain + ;(function() { + this; + should(); + too(); + })(); + +%script(type="text/javascript") + :plain + // + +%script(type="text/html") + I'm a jQuery {{template}}. \ No newline at end of file diff --git a/middleman-more/fixtures/minify-js-app/source/more-js/other.js b/middleman-more/fixtures/minify-js-app/source/more-js/other.js new file mode 100644 index 00000000..f6a9406c --- /dev/null +++ b/middleman-more/fixtures/minify-js-app/source/more-js/other.js @@ -0,0 +1,8 @@ +var race; +var __slice = Array.prototype.slice; + +race = function() { + var runners, winner; + winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : []; + return print(winner, runners); +}; diff --git a/middleman-more/fixtures/passthrough-app/config.rb b/middleman-more/fixtures/passthrough-app/config.rb index 1c7fbe6d..1f6349db 100644 --- a/middleman-more/fixtures/passthrough-app/config.rb +++ b/middleman-more/fixtures/passthrough-app/config.rb @@ -4,14 +4,14 @@ module ::PassThrough end end -set :js_compressor, ::PassThrough -set :css_compressor, ::PassThrough - activate :minify_javascript activate :minify_css +set :js_compressor, ::PassThrough +set :css_compressor, ::PassThrough + with_layout false do page "/inline-css.html" page "/inline-js.html" page "/inline-coffeescript.html" -end \ No newline at end of file +end diff --git a/middleman-more/fixtures/passthrough-app/source/inline-css.html.haml b/middleman-more/fixtures/passthrough-app/source/inline-css.html.haml index 36c2c8e4..163b4395 100755 --- a/middleman-more/fixtures/passthrough-app/source/inline-css.html.haml +++ b/middleman-more/fixtures/passthrough-app/source/inline-css.html.haml @@ -1,4 +1,5 @@ -:sass - body - test: style - good: deal \ No newline at end of file +%style(type="text/css") + :sass + body + test: style + good: deal \ No newline at end of file diff --git a/middleman-more/fixtures/passthrough-app/source/inline-js.html.haml b/middleman-more/fixtures/passthrough-app/source/inline-js.html.haml index 06197239..7b383e47 100755 --- a/middleman-more/fixtures/passthrough-app/source/inline-js.html.haml +++ b/middleman-more/fixtures/passthrough-app/source/inline-js.html.haml @@ -4,4 +4,25 @@ should(); all.be(); on = { one: line }; - })(); \ No newline at end of file + })(); + +%script + :plain + ;(function() { + this; + should(); + too(); + })(); + +%script(type="text/javascript") + :plain + // + +%script(type="text/html") + I'm a jQuery {{template}}. \ No newline at end of file diff --git a/middleman-more/lib/middleman-more/core_extensions/sprockets.rb b/middleman-more/lib/middleman-more/core_extensions/sprockets.rb index 70ed3371..e51e0b9a 100644 --- a/middleman-more/lib/middleman-more/core_extensions/sprockets.rb +++ b/middleman-more/lib/middleman-more/core_extensions/sprockets.rb @@ -9,10 +9,6 @@ module Middleman::CoreExtensions::Sprockets # Once registered def registered(app) - # Default compression to off - app.set :js_compressor, false - app.set :css_compressor, false - # Add class methods to context app.send :include, InstanceMethods @@ -70,28 +66,10 @@ module Middleman::CoreExtensions::Sprockets end end - # Remove old compressors + # Remove compressors, we handle these with middleware unregister_bundle_processor 'application/javascript', :js_compressor unregister_bundle_processor 'text/css', :css_compressor - # Register compressor from config - register_bundle_processor 'application/javascript', :js_compressor do |context, data| - if context.pathname.to_s =~ /\.min\./ - data - else - app.js_compressor.compress(data) - end - end if app.js_compressor - - # Register compressor from config - register_bundle_processor 'text/css', :css_compressor do |context, data| - if context.pathname.to_s =~ /\.min\./ - data - else - app.css_compressor.compress(data) - end - end if app.css_compressor - # configure search paths append_path app.js_dir append_path app.css_dir diff --git a/middleman-more/lib/middleman-more/extensions/asset_hash.rb b/middleman-more/lib/middleman-more/extensions/asset_hash.rb index f0f3011b..f3a14331 100755 --- a/middleman-more/lib/middleman-more/extensions/asset_hash.rb +++ b/middleman-more/lib/middleman-more/extensions/asset_hash.rb @@ -53,18 +53,7 @@ module Middleman::Extensions dirpath = Pathname.new(File.dirname(path)) if path =~ /(^\/$)|(\.(htm|html|php|css|js)$)/ - body = case(response) - when String - response - when Array - response.join - when Rack::Response - response.body.join - when Rack::File - File.read(response.path) - else - response.to_s - end + body = extract_response_text(response) if body # TODO: This regex will change some paths in plan HTML (not in a tag) - is that OK? @@ -90,6 +79,23 @@ module Middleman::Extensions end [status, headers, response] end + + private + + def extract_response_text(response) + case(response) + when String + response + when Array + response.join + when Rack::Response + response.body.join + when Rack::File + File.read(response.path) + else + response.to_s + end + end end end diff --git a/middleman-more/lib/middleman-more/extensions/minify_css.rb b/middleman-more/lib/middleman-more/extensions/minify_css.rb index f90c8848..e373963d 100644 --- a/middleman-more/lib/middleman-more/extensions/minify_css.rb +++ b/middleman-more/lib/middleman-more/extensions/minify_css.rb @@ -9,18 +9,84 @@ module Middleman::Extensions # Once registered def registered(app) - # Tell Sprockets to use the built in CSSMin + app.set :css_compressor, false + app.after_configuration do - if !css_compressor + unless respond_to?(:css_compressor) && css_compressor require "middleman-more/extensions/minify_css/rainpress" set :css_compressor, ::Rainpress end + + # Setup Rack to watch for inline JS + use InlineCSSRack, :compressor => css_compressor end end alias :included :registered end end - + + # Rack middleware to look for JS in HTML and compress it + class InlineCSSRack + + # Init + # @param [Class] app + # @param [Hash] options + def initialize(app, options={}) + @app = app + @compressor = options[:compressor] + end + + # Rack interface + # @param [Rack::Environmemt] env + # @return [Array] + def call(env) + status, headers, response = @app.call(env) + + path = env["PATH_INFO"] + + if path.end_with?('.html') || path.end_with?('.php') + uncompressed_source = extract_response_text(response) + + minified = uncompressed_source.gsub(/(]*?>\s*(?:\/\*\*\/)?\s*<\/style>)/m) do |match| + first = $1 + css = $2 + last = $3 + + minified_css = @compressor.compress(css) + + first << minified_css << last + end + + headers["Content-Length"] = ::Rack::Utils.bytesize(minified).to_s + response = [minified] + elsif path.end_with?('.css') && path !~ /\.min\./ + uncompressed_source = extract_response_text(response) + minified_css = @compressor.compress(uncompressed_source) + + headers["Content-Length"] = ::Rack::Utils.bytesize(minified_css).to_s + response = [minified_css] + end + + [status, headers, response] + end + + private + + def extract_response_text(response) + case(response) + when String + response + when Array + response.join + when Rack::Response + response.body.join + when Rack::File + File.read(response.path) + else + response.to_s + end + end + end # Register extension # register :minify_css, MinifyCss -end \ No newline at end of file +end diff --git a/middleman-more/lib/middleman-more/extensions/minify_javascript.rb b/middleman-more/lib/middleman-more/extensions/minify_javascript.rb index 390e60b3..0e459dc9 100755 --- a/middleman-more/lib/middleman-more/extensions/minify_javascript.rb +++ b/middleman-more/lib/middleman-more/extensions/minify_javascript.rb @@ -9,12 +9,11 @@ module Middleman::Extensions # Once registered def registered(app) - + app.set :js_compressor, false + # Once config is parsed app.after_configuration do - - # Tell sprockets which compressor to use - if !js_compressor + unless respond_to?(:js_compressor) && js_compressor require 'uglifier' set :js_compressor, ::Uglifier.new end @@ -43,35 +42,60 @@ module Middleman::Extensions def call(env) status, headers, response = @app.call(env) - if env["PATH_INFO"].match(/\.html$/) - uncompressed_source = case(response) - when String - response - when Array - response.join - when Rack::Response - response.body.join - when Rack::File - File.read(response.path) - end + path = env["PATH_INFO"] - minified = uncompressed_source.gsub(/()/m) do |m| + if path.end_with?('.html') || path.end_with?('.php') + uncompressed_source = extract_response_text(response) + + minified = uncompressed_source.gsub(/(]*?>\s*(?:\/\/(?:(?:)|(?:\]\]>)))?\s*<\/script>)/m) do |match| first = $1 - uncompressed_source = $2 + javascript = $2 last = $3 - minified_js = @compressor.compress(uncompressed_source) - first << minified_js << "\n" << last + # Only compress script tags that contain JavaScript (as opposed + # to something like jQuery templates, identified with a "text/html" + # type. + if first =~ /