Skip to content
Browse files

Merge pull request #341 from bhollis/asset_hash

asset_hash considers output file contents for hash
  • Loading branch information...
2 parents 30c41df + fc79459 commit 67a84c0c9b29d50f58902801629e85d14332f319 @tdreyno tdreyno committed Apr 4, 2012
View
9 middleman-core/lib/middleman-core/cli/build.rb
@@ -98,10 +98,10 @@ def source_root
# 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 @@ def render_to_file(page)
say_status :error, output_file, :red
raise Thor::Error.new $!
end
+
+ output_file
end
end
@@ -219,9 +221,8 @@ def execute!
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
View
26 middleman-core/lib/middleman-core/sitemap/page.rb
@@ -116,15 +116,17 @@ def ignore
# 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 @@ def relative_path
# 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 @@ def touch
# Clear the cache if the file is deleted
# @return [void]
def delete
- cache.clear
+ touch
end
protected
View
1 middleman-core/lib/middleman-core/sitemap/store.rb
@@ -94,7 +94,6 @@ def page(path)
# @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 ||
View
64 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')"
+ # 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'
+
View
1 middleman-more/fixtures/asset-hash-app/source/partials.html.erb
@@ -0,0 +1 @@
+<%= stylesheet_link_tag 'uses_partials' %>
View
2 middleman-more/fixtures/asset-hash-app/source/stylesheets/_partial.sass
@@ -0,0 +1,2 @@
+body
+ font-size: 18px
View
4 middleman-more/fixtures/asset-hash-app/source/stylesheets/uses_partials.css.sass
@@ -0,0 +1,4 @@
+@import partial.sass
+
+red
+ color: blue
View
94 middleman-more/lib/middleman-more/core_extensions/sprockets.rb
@@ -13,44 +13,51 @@ def registered(app)
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_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
+ try_paths = root_paths.map {|rp| File.join(rp, 'javascripts') } +
+ root_paths.map {|rp| File.join(rp, 'stylesheets') }
+
+ ([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 @@ def method_missing(name)
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 @@ def initialize(app)
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 @@ def initialize(app)
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
View
21 middleman-more/lib/middleman-more/extensions/asset_hash.rb
@@ -8,10 +8,25 @@ def registered(app, options)
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

0 comments on commit 67a84c0

Please sign in to comment.
Something went wrong with that request. Please try again.