diff --git a/middleman-core/lib/middleman-core/cli/build.rb b/middleman-core/lib/middleman-core/cli/build.rb index e4ab33b8..04153db2 100644 --- a/middleman-core/lib/middleman-core/cli/build.rb +++ b/middleman-core/lib/middleman-core/cli/build.rb @@ -98,10 +98,10 @@ module Middleman::Cli # Render a page to a file. # # @param [Middleman::Sitemap::Page] page - # @return [void] + # @return [String] The full path of the file that was written def render_to_file(page) build_dir = self.class.shared_instance.build_dir - output_file = File.join(self.class.shared_instance.build_dir, page.destination_path) + output_file = File.join(build_dir, page.destination_path) begin response = self.class.shared_rack.get(page.request_path.gsub(/\s/, "%20")) @@ -114,6 +114,8 @@ module Middleman::Cli say_status :error, output_file, :red raise Thor::Error.new $! end + + output_file end end @@ -219,9 +221,8 @@ module Middleman::Cli next if page.ignored? next if @config[:glob] && !File.fnmatch(@config[:glob], page.path) - base.render_to_file(page) + output_path = base.render_to_file(page) - output_path = File.join(@destination, page.destination_path) @cleaning_queue.delete(Pathname.new(output_path).realpath) if cleaning? end end diff --git a/middleman-core/lib/middleman-core/sitemap/page.rb b/middleman-core/lib/middleman-core/sitemap/page.rb index e2470716..99d1a2d0 100644 --- a/middleman-core/lib/middleman-core/sitemap/page.rb +++ b/middleman-core/lib/middleman-core/sitemap/page.rb @@ -116,15 +116,17 @@ module Middleman::Sitemap # Render this page # @return [String] def render(*args, &block) - return unless template? - - if proxy? - t = store.page(proxied_to).template - t.request_path = path - t.render(*args) - else - template.request_path = path - template.render(*args, &block) + if template? + if proxy? + t = store.page(proxied_to).template + t.request_path = path + t.render(*args) + else + template.request_path = path + template.render(*args, &block) + end + else # just a static file + File.open(source_file).read end end @@ -167,9 +169,7 @@ module Middleman::Sitemap # This path can be affected by proxy callbacks. # @return [String] def destination_path - # memoizing this means that reroute callbacks should be in place before the sitemap - # gets built - @destination_path ||= store.reroute_callbacks.inject(self.path) do |destination, callback| + store.reroute_callbacks.inject(self.path) do |destination, callback| callback.call(destination, self) end end @@ -256,7 +256,7 @@ module Middleman::Sitemap # Clear the cache if the file is deleted # @return [void] def delete - cache.clear + touch end protected diff --git a/middleman-core/lib/middleman-core/sitemap/store.rb b/middleman-core/lib/middleman-core/sitemap/store.rb index f6f43fb0..7bc83f65 100644 --- a/middleman-core/lib/middleman-core/sitemap/store.rb +++ b/middleman-core/lib/middleman-core/sitemap/store.rb @@ -94,7 +94,6 @@ module Middleman::Sitemap # @param [String] The destination (output) path of a page. # @return [Middleman::Sitemap::Page] def page_by_destination(destination_path) - # TODO: memoize this destination_path = normalize_path(destination_path) pages.find do |p| p.destination_path == destination_path || diff --git a/middleman-more/features/asset_hash.feature b/middleman-more/features/asset_hash.feature index ec4938be..856693ef 100644 --- a/middleman-more/features/asset_hash.feature +++ b/middleman-more/features/asset_hash.feature @@ -7,8 +7,8 @@ Feature: Assets get a file hash appended to their and references to them are upd | images/100px-1242c368.png | | images/100px-5fd6fb90.jpg | | images/100px-5fd6fb90.gif | - | javascripts/application-1d8d5276.js | - | stylesheets/site-8c28fde3.css | + | javascripts/application-570e5d45.js | + | stylesheets/site-d9d84711.css | | index.html | | subdir/index.html | | other/index.html | @@ -19,48 +19,66 @@ Feature: Assets get a file hash appended to their and references to them are upd | javascripts/application.js | | stylesheets/site.css | - And the file "javascripts/application-1d8d5276.js" should contain "img.src = '/images/100px-5fd6fb90.jpg'" - And the file "stylesheets/site-8c28fde3.css" should contain "background-image: url('../images/100px-5fd6fb90.jpg')" - And the file "index.html" should contain 'href="stylesheets/site-8c28fde3.css"' - And the file "index.html" should contain 'src="javascripts/application-1d8d5276.js"' + And the file "javascripts/application-570e5d45.js" should contain "img.src = '/images/100px-5fd6fb90.jpg'" + And the file "stylesheets/site-d9d84711.css" should contain "background-image: url('../images/100px-5fd6fb90.jpg')" + And the file "index.html" should contain 'href="stylesheets/site-d9d84711.css"' + And the file "index.html" should contain 'src="javascripts/application-570e5d45.js"' And the file "index.html" should contain 'src="images/100px-5fd6fb90.jpg"' - And the file "subdir/index.html" should contain 'href="../stylesheets/site-8c28fde3.css"' - And the file "subdir/index.html" should contain 'src="../javascripts/application-1d8d5276.js"' + And the file "subdir/index.html" should contain 'href="../stylesheets/site-d9d84711.css"' + And the file "subdir/index.html" should contain 'src="../javascripts/application-570e5d45.js"' And the file "subdir/index.html" should contain 'src="../images/100px-5fd6fb90.jpg"' - And the file "other/index.html" should contain 'href="../stylesheets/site-8c28fde3.css"' - And the file "other/index.html" should contain 'src="../javascripts/application-1d8d5276.js"' + And the file "other/index.html" should contain 'href="../stylesheets/site-d9d84711.css"' + And the file "other/index.html" should contain 'src="../javascripts/application-570e5d45.js"' And the file "other/index.html" should contain 'src="../images/100px-5fd6fb90.jpg"' Scenario: Hashed assets work in preview server Given the Server is running at "asset-hash-app" When I go to "/" - Then I should see 'href="stylesheets/site-8c28fde3.css"' - And I should see 'src="javascripts/application-1d8d5276.js"' + Then I should see 'href="stylesheets/site-d9d84711.css"' + And I should see 'src="javascripts/application-570e5d45.js"' And I should see 'src="images/100px-5fd6fb90.jpg"' When I go to "/subdir/" - Then I should see 'href="../stylesheets/site-8c28fde3.css"' - And I should see 'src="../javascripts/application-1d8d5276.js"' + Then I should see 'href="../stylesheets/site-d9d84711.css"' + And I should see 'src="../javascripts/application-570e5d45.js"' And I should see 'src="../images/100px-5fd6fb90.jpg"' When I go to "/other/" - Then I should see 'href="../stylesheets/site-8c28fde3.css"' - And I should see 'src="../javascripts/application-1d8d5276.js"' + Then I should see 'href="../stylesheets/site-d9d84711.css"' + And I should see 'src="../javascripts/application-570e5d45.js"' And I should see 'src="../images/100px-5fd6fb90.jpg"' - When I go to "/javascripts/application-1d8d5276.js" + When I go to "/javascripts/application-570e5d45.js" Then I should see "img.src = '/images/100px-5fd6fb90.jpg'" - When I go to "/stylesheets/site-8c28fde3.css" + When I go to "/stylesheets/site-d9d84711.css" Then I should see "background-image: url('../images/100px-5fd6fb90.jpg')" Scenario: Enabling an asset host still produces hashed files and references Given the Server is running at "asset-hash-host-app" When I go to "/" - Then I should see 'href="http://middlemanapp.com/stylesheets/site-8c28fde3.css"' + Then I should see 'href="http://middlemanapp.com/stylesheets/site-0ac82771.css"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"' When I go to "/subdir/" - Then I should see 'href="http://middlemanapp.com/stylesheets/site-8c28fde3.css"' + Then I should see 'href="http://middlemanapp.com/stylesheets/site-0ac82771.css"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"' When I go to "/other/" - Then I should see 'href="http://middlemanapp.com/stylesheets/site-8c28fde3.css"' + Then I should see 'href="http://middlemanapp.com/stylesheets/site-0ac82771.css"' And I should see 'src="http://middlemanapp.com/images/100px-5fd6fb90.jpg"' # Asset helpers don't appear to work from Compass right now - # When I go to "/stylesheets/site-8c28fde3.css" - # Then I should see "background-image: url('http://middlemanapp.com/images/100px-5fd6fb90.jpg')" \ No newline at end of file + # When I go to "/stylesheets/site-0ac82771.css" + # Then I should see "background-image: url('http://middlemanapp.com/images/100px-5fd6fb90.jpg')" + + Scenario: The asset hash should change when a SASS or Sprockets partial changes + Given the Server is running at "asset-hash-app" + And the file "source/stylesheets/_partial.sass" has the contents + """ + body + font-size: 14px + """ + When I go to "/partials/" + Then I should see 'href="../stylesheets/uses_partials-e81dd9b4.css' + And the file "source/stylesheets/_partial.sass" has the contents + """ + body + font-size: 18px !important + """ + When I go to "/partials/" + Then I should see 'href="../stylesheets/uses_partials-ba3ef309.css' + diff --git a/middleman-more/fixtures/asset-hash-app/source/partials.html.erb b/middleman-more/fixtures/asset-hash-app/source/partials.html.erb new file mode 100644 index 00000000..6b5aa4bf --- /dev/null +++ b/middleman-more/fixtures/asset-hash-app/source/partials.html.erb @@ -0,0 +1 @@ +<%= stylesheet_link_tag 'uses_partials' %> diff --git a/middleman-more/fixtures/asset-hash-app/source/stylesheets/_partial.sass b/middleman-more/fixtures/asset-hash-app/source/stylesheets/_partial.sass new file mode 100644 index 00000000..3b0e67db --- /dev/null +++ b/middleman-more/fixtures/asset-hash-app/source/stylesheets/_partial.sass @@ -0,0 +1,2 @@ +body + font-size: 18px \ No newline at end of file diff --git a/middleman-more/fixtures/asset-hash-app/source/stylesheets/uses_partials.css.sass b/middleman-more/fixtures/asset-hash-app/source/stylesheets/uses_partials.css.sass new file mode 100644 index 00000000..66b4dfd6 --- /dev/null +++ b/middleman-more/fixtures/asset-hash-app/source/stylesheets/uses_partials.css.sass @@ -0,0 +1,4 @@ +@import partial.sass + +red + color: blue \ 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 c0f1c996..70ed3371 100644 --- a/middleman-more/lib/middleman-more/core_extensions/sprockets.rb +++ b/middleman-more/lib/middleman-more/core_extensions/sprockets.rb @@ -13,44 +13,51 @@ module Middleman::CoreExtensions::Sprockets app.set :js_compressor, false app.set :css_compressor, false + # Add class methods to context + app.send :include, InstanceMethods + # Once Middleman is setup app.ready do - # Create sprockets env for JS and CSS - js_env = Middleman::CoreExtensions::Sprockets::JavascriptEnvironment.new(self) - css_env = Middleman::CoreExtensions::Sprockets::StylesheetEnvironment.new(self) - # Add any gems with (vendor|app|.)/assets/javascripts to paths # also add similar directories from project root (like in rails) root_paths = [%w{ app }, %w{ assets }, %w{ vendor }, %w{ app assets }, %w{ vendor assets }] - try_js_paths = root_paths.map{|rp| File.join(rp, 'javascripts')} - try_css_paths = root_paths.map{|rp| File.join(rp, 'stylesheets')} + try_paths = root_paths.map {|rp| File.join(rp, 'javascripts') } + + root_paths.map {|rp| File.join(rp, 'stylesheets') } - { try_js_paths => js_env, try_css_paths => css_env }.each do |paths, env| - ([root] + ::Middleman.rubygems_latest_specs.map(&:full_gem_path)).each do |root_path| - paths.map{|p| File.join(root_path, p)}. - select{|p| File.directory?(p)}. - each{|path| env.append_path(path)} - end + ([root] + ::Middleman.rubygems_latest_specs.map(&:full_gem_path)).each do |root_path| + try_paths.map {|p| File.join(root_path, p) }. + select {|p| File.directory?(p) }. + each {|path| sprockets.append_path(path) } end # Setup Sprockets Sass options sass.each { |k, v| ::Sprockets::Sass.options[k] = v } # Intercept requests to /javascripts and /stylesheets and pass to sprockets - map("/#{js_dir}") { run js_env } - map("/#{css_dir}"){ run css_env } + our_sprockets = sprockets + map("/#{js_dir}") { run our_sprockets } + map("/#{css_dir}") { run our_sprockets } end end alias :included :registered end + module InstanceMethods + # @return [Middleman::CoreExtensions::Sprockets::MiddlemanSprocketsEnvironment] + def sprockets + @sprockets ||= MiddlemanSprocketsEnvironment.new(self) + end + end + # Generic Middleman Sprockets env - class MiddlemanEnvironment < ::Sprockets::Environment + class MiddlemanSprocketsEnvironment < ::Sprockets::Environment # Setup def initialize(app) @app = app super app.source_dir + digest = Digest::SHA1 + # Make the app context available to Sprockets context_class.send(:define_method, :app) { app } context_class.class_eval do @@ -62,26 +69,10 @@ module Middleman::CoreExtensions::Sprockets end end end - end - # During development, don't use the asset cache - def find_asset(path, options = {}) - expire_index! if @app.development? - super - end - end - - # Javascript specific environment - class JavascriptEnvironment < MiddlemanEnvironment - - # Init - def initialize(app) - super - - expire_index! - - # Remove old compressor + # Remove old compressors 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| @@ -92,29 +83,6 @@ module Middleman::CoreExtensions::Sprockets end end if app.js_compressor - # configure search paths - append_path app.js_dir - end - - # Clear cache on error - def javascript_exception_response(exception) - expire_index! - super(exception) - end - end - - # CSS specific environment - class StylesheetEnvironment < MiddlemanEnvironment - - # Init - def initialize(app) - super - - expire_index! - - # Remove old compressor - unregister_bundle_processor 'text/css', :css_compressor - # Register compressor from config register_bundle_processor 'text/css', :css_compressor do |context, data| if context.pathname.to_s =~ /\.min\./ @@ -125,13 +93,23 @@ module Middleman::CoreExtensions::Sprockets end if app.css_compressor # configure search paths + append_path app.js_dir append_path app.css_dir end + # During development, don't use the asset cache + def find_asset(path, options = {}) + expire_index! if @app.development? + super + end + # Clear cache on error - def css_exception_response(exception) + def javascript_exception_response(exception) expire_index! super(exception) end + + # Clear cache on error + alias :css_exception_response :javascript_exception_response end end diff --git a/middleman-more/lib/middleman-more/extensions/asset_hash.rb b/middleman-more/lib/middleman-more/extensions/asset_hash.rb index 3461fc36..f0f3011b 100755 --- a/middleman-more/lib/middleman-more/extensions/asset_hash.rb +++ b/middleman-more/lib/middleman-more/extensions/asset_hash.rb @@ -8,10 +8,25 @@ module Middleman::Extensions app.after_configuration do sitemap.reroute do |destination, page| if exts.include? page.ext - page.cache.fetch(:asset_hash) do - digest = Digest::SHA1.file(page.source_file).hexdigest[0..7] - destination.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" } + # figure out the path Sprockets would use for this asset + if page.ext == '.js' + sprockets_path = page.path.sub(js_dir,'').sub(/^\//,'') + elsif page.ext == '.css' + sprockets_path = page.path.sub(css_dir,'').sub(/^\//,'') end + + # See if Sprockets knows about the file + asset = sprockets.find_asset(sprockets_path) if sprockets_path + + if asset # if it's a Sprockets asset, ask sprockets for its digest + digest = asset.digest[0..7] + elsif page.template? # if it's a template, render it out + digest = Digest::SHA1.hexdigest(page.render)[0..7] + else # if it's a static file, just hash it + digest = Digest::SHA1.file(page.source_file).hexdigest[0..7] + end + + destination.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" } else destination end