Extension to add hash values to asset filenames. This extension causes asset file types (images, scripts, stylesheets, etc) to have a unique identifier appended to their filename that consists of a hash of their contents. This extension also includes a Rack middleware that rewrites references to these assets in HTML, JavaScript, and CSS files, eliminating the need to use special helper functions to include modified filenames in references.

This commit is contained in:
Ben Hollis 2012-03-04 15:24:38 -08:00
parent c2f498e26e
commit 073086b79c
14 changed files with 822 additions and 1 deletions

View file

@ -44,3 +44,8 @@ Given /^a successfully built app at "([^\"]*)" with flags "([^\"]*)"$/ do |path,
step %Q{a built app at "#{path}" with flags "#{flags}"} step %Q{a built app at "#{path}" with flags "#{flags}"}
step %Q{was successfully built} step %Q{was successfully built}
end end
# Provide this Aruba overload in case we're matching something with quotes in it
Then /^the file "([^"]*)" should contain '([^']*)'$/ do |file, partial_content|
check_file_content(file, partial_content, true)
end

View file

@ -0,0 +1,55 @@
Feature: Assets get a file hash appended to their and references to them are updated
Scenario: Hashed-asset files are produced, and HTML, CSS, and JavaScript gets rewritten to reference the new files
Given a successfully built app at "asset-hash-app"
When I cd to "build"
Then the following files should exist:
| index.html |
| images/100px-1242c368.png |
| images/100px-5fd6fb90.jpg |
| images/100px-5fd6fb90.gif |
| javascripts/application-1d8d5276.js |
| stylesheets/site-92072d15.css |
| index.html |
| subdir/index.html |
| other/index.html |
And the following files should not exist:
| images/100px.png |
| images/100px.jpg |
| images/100px.gif |
| javascripts/application.js |
| stylesheets/site.css |
And the file "javascripts/application-1d8d5276.js" should contain "img.src = '/images/100px-5fd6fb90.jpg'"
# TODO: This stylesheet should use the SASS "image-url" helper but can't because of https://github.com/middleman/middleman/issues/283
And the file "stylesheets/site-92072d15.css" should contain 'background-image: url("/images/100px-5fd6fb90.jpg")'
And the file "index.html" should contain 'link href="stylesheets/site-92072d15.css"'
And the file "index.html" should contain 'script src="javascripts/application-1d8d5276.js"'
And the file "index.html" should contain 'img src="images/100px-5fd6fb90.jpg"'
And the file "subdir/index.html" should contain 'link href="../stylesheets/site-92072d15.css"'
And the file "subdir/index.html" should contain 'script src="../javascripts/application-1d8d5276.js"'
And the file "subdir/index.html" should contain 'img src="../images/100px-5fd6fb90.jpg"'
And the file "other/index.html" should contain 'link href="../stylesheets/site-92072d15.css"'
And the file "other/index.html" should contain 'script src="../javascripts/application-1d8d5276.js"'
And the file "other/index.html" should contain 'img 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 'link href="stylesheets/site-92072d15.css"'
And I should see 'script src="javascripts/application-1d8d5276.js"'
And I should see 'img src="images/100px-5fd6fb90.jpg"'
When I go to "/subdir/"
Then I should see 'link href="../stylesheets/site-92072d15.css"'
And I should see 'script src="../javascripts/application-1d8d5276.js"'
And I should see 'img src="../images/100px-5fd6fb90.jpg"'
When I go to "/other/"
Then I should see 'link href="../stylesheets/site-92072d15.css"'
And I should see 'script src="../javascripts/application-1d8d5276.js"'
And I should see 'img src="../images/100px-5fd6fb90.jpg"'
When I go to "/javascripts/application-1d8d5276.js"
Then I should see "img.src = '/images/100px-5fd6fb90.jpg'"
When I go to "/stylesheets/site-92072d15.css"
Then I should see 'background-image: url("/images/100px-5fd6fb90.jpg")'
Scenario: Enabling an asset host still produces hashed files and references

View file

@ -0,0 +1,8 @@
activate :asset_hash
activate :relative_assets
activate :directory_indexes
#page '/foo.html', :directory_index => false

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

View file

@ -0,0 +1,308 @@
<% content_for :head do %>
<title>The Middleman!</title>
<% end %>
<h2>Image url:</h2>
<img src="<%= image_path('100px.jpg') %>">
<h2>Autogenerated tests:</h2>
<p>images/100px.jpg</p>
<p>/images/100px.jpg</p>
<p>../images/100px.jpg</p>
<p>../../images/100px.jpg</p>
<p>../../../images/100px.jpg</p>
<p>http://example.com/images/100px.jpg</p>
<p>aimages/100px.jpga</p>
<p>1images/100px.jpg1</p>
<p>.images/100px.jpg.</p>
<p>-images/100px.jpg-</p>
<p>_images/100px.jpg_</p>
<p>'images/100px.jpg'</p>
<p>'/images/100px.jpg'</p>
<p>'../images/100px.jpg'</p>
<p>'../../images/100px.jpg'</p>
<p>'../../../images/100px.jpg'</p>
<p>'http://example.com/images/100px.jpg'</p>
<p>'aimages/100px.jpga'</p>
<p>'1images/100px.jpg1'</p>
<p>'.images/100px.jpg.'</p>
<p>'-images/100px.jpg-'</p>
<p>'_images/100px.jpg_'</p>
<p>"images/100px.jpg"</p>
<p>"/images/100px.jpg"</p>
<p>"../images/100px.jpg"</p>
<p>"../../images/100px.jpg"</p>
<p>"../../../images/100px.jpg"</p>
<p>"http://example.com/images/100px.jpg"</p>
<p>"aimages/100px.jpga"</p>
<p>"1images/100px.jpg1"</p>
<p>".images/100px.jpg."</p>
<p>"-images/100px.jpg-"</p>
<p>"_images/100px.jpg_"</p>
<p>&lt;img src=images/100px.jpg /&gt;</p>
<p>&lt;img src=/images/100px.jpg /&gt;</p>
<p>&lt;img src=../images/100px.jpg /&gt;</p>
<p>&lt;img src=../../images/100px.jpg /&gt;</p>
<p>&lt;img src=../../../images/100px.jpg /&gt;</p>
<p>&lt;img src=http://example.com/images/100px.jpg /&gt;</p>
<p>&lt;img src=aimages/100px.jpga /&gt;</p>
<p>&lt;img src=1images/100px.jpg1 /&gt;</p>
<p>&lt;img src=.images/100px.jpg. /&gt;</p>
<p>&lt;img src=-images/100px.jpg- /&gt;</p>
<p>&lt;img src=_images/100px.jpg_ /&gt;</p>
<p>&lt;img src='images/100px.jpg' /&gt;</p>
<p>&lt;img src='/images/100px.jpg' /&gt;</p>
<p>&lt;img src='../images/100px.jpg' /&gt;</p>
<p>&lt;img src='../../images/100px.jpg' /&gt;</p>
<p>&lt;img src='../../../images/100px.jpg' /&gt;</p>
<p>&lt;img src='http://example.com/images/100px.jpg' /&gt;</p>
<p>&lt;img src='aimages/100px.jpga' /&gt;</p>
<p>&lt;img src='1images/100px.jpg1' /&gt;</p>
<p>&lt;img src='.images/100px.jpg.' /&gt;</p>
<p>&lt;img src='-images/100px.jpg-' /&gt;</p>
<p>&lt;img src='_images/100px.jpg_' /&gt;</p>
<p>&lt;img src="images/100px.jpg" /&gt;</p>
<p>&lt;img src="/images/100px.jpg" /&gt;</p>
<p>&lt;img src="../images/100px.jpg" /&gt;</p>
<p>&lt;img src="../../images/100px.jpg" /&gt;</p>
<p>&lt;img src="../../../images/100px.jpg" /&gt;</p>
<p>&lt;img src="http://example.com/images/100px.jpg" /&gt;</p>
<p>&lt;img src="aimages/100px.jpga" /&gt;</p>
<p>&lt;img src="1images/100px.jpg1" /&gt;</p>
<p>&lt;img src=".images/100px.jpg." /&gt;</p>
<p>&lt;img src="-images/100px.jpg-" /&gt;</p>
<p>&lt;img src="_images/100px.jpg_" /&gt;</p>
<p>background-image:url(images/100px.jpg);</p>
<p>background-image:url(/images/100px.jpg);</p>
<p>background-image:url(../images/100px.jpg);</p>
<p>background-image:url(../../images/100px.jpg);</p>
<p>background-image:url(../../../images/100px.jpg);</p>
<p>background-image:url(http://example.com/images/100px.jpg);</p>
<p>background-image:url(aimages/100px.jpga);</p>
<p>background-image:url(1images/100px.jpg1);</p>
<p>background-image:url(.images/100px.jpg.);</p>
<p>background-image:url(-images/100px.jpg-);</p>
<p>background-image:url(_images/100px.jpg_);</p>
<p>background-image:url('images/100px.jpg');</p>
<p>background-image:url('/images/100px.jpg');</p>
<p>background-image:url('../images/100px.jpg');</p>
<p>background-image:url('../../images/100px.jpg');</p>
<p>background-image:url('../../../images/100px.jpg');</p>
<p>background-image:url('http://example.com/images/100px.jpg');</p>
<p>background-image:url('aimages/100px.jpga');</p>
<p>background-image:url('1images/100px.jpg1');</p>
<p>background-image:url('.images/100px.jpg.');</p>
<p>background-image:url('-images/100px.jpg-');</p>
<p>background-image:url('_images/100px.jpg_');</p>
<p>background-image:url("images/100px.jpg");</p>
<p>background-image:url("/images/100px.jpg");</p>
<p>background-image:url("../images/100px.jpg");</p>
<p>background-image:url("../../images/100px.jpg");</p>
<p>background-image:url("../../../images/100px.jpg");</p>
<p>background-image:url("http://example.com/images/100px.jpg");</p>
<p>background-image:url("aimages/100px.jpga");</p>
<p>background-image:url("1images/100px.jpg1");</p>
<p>background-image:url(".images/100px.jpg.");</p>
<p>background-image:url("-images/100px.jpg-");</p>
<p>background-image:url("_images/100px.jpg_");</p>
<br /><br /><br />
<p>images/100px.png</p>
<p>/images/100px.png</p>
<p>../images/100px.png</p>
<p>../../images/100px.png</p>
<p>../../../images/100px.png</p>
<p>http://example.com/images/100px.png</p>
<p>aimages/100px.pnga</p>
<p>1images/100px.png1</p>
<p>.images/100px.png.</p>
<p>-images/100px.png-</p>
<p>_images/100px.png_</p>
<p>'images/100px.png'</p>
<p>'/images/100px.png'</p>
<p>'../images/100px.png'</p>
<p>'../../images/100px.png'</p>
<p>'../../../images/100px.png'</p>
<p>'http://example.com/images/100px.png'</p>
<p>'aimages/100px.pnga'</p>
<p>'1images/100px.png1'</p>
<p>'.images/100px.png.'</p>
<p>'-images/100px.png-'</p>
<p>'_images/100px.png_'</p>
<p>"images/100px.png"</p>
<p>"/images/100px.png"</p>
<p>"../images/100px.png"</p>
<p>"../../images/100px.png"</p>
<p>"../../../images/100px.png"</p>
<p>"http://example.com/images/100px.png"</p>
<p>"aimages/100px.pnga"</p>
<p>"1images/100px.png1"</p>
<p>".images/100px.png."</p>
<p>"-images/100px.png-"</p>
<p>"_images/100px.png_"</p>
<p>&lt;img src=images/100px.png /&gt;</p>
<p>&lt;img src=/images/100px.png /&gt;</p>
<p>&lt;img src=../images/100px.png /&gt;</p>
<p>&lt;img src=../../images/100px.png /&gt;</p>
<p>&lt;img src=../../../images/100px.png /&gt;</p>
<p>&lt;img src=http://example.com/images/100px.png /&gt;</p>
<p>&lt;img src=aimages/100px.pnga /&gt;</p>
<p>&lt;img src=1images/100px.png1 /&gt;</p>
<p>&lt;img src=.images/100px.png. /&gt;</p>
<p>&lt;img src=-images/100px.png- /&gt;</p>
<p>&lt;img src=_images/100px.png_ /&gt;</p>
<p>&lt;img src='images/100px.png' /&gt;</p>
<p>&lt;img src='/images/100px.png' /&gt;</p>
<p>&lt;img src='../images/100px.png' /&gt;</p>
<p>&lt;img src='../../images/100px.png' /&gt;</p>
<p>&lt;img src='../../../images/100px.png' /&gt;</p>
<p>&lt;img src='http://example.com/images/100px.png' /&gt;</p>
<p>&lt;img src='aimages/100px.pnga' /&gt;</p>
<p>&lt;img src='1images/100px.png1' /&gt;</p>
<p>&lt;img src='.images/100px.png.' /&gt;</p>
<p>&lt;img src='-images/100px.png-' /&gt;</p>
<p>&lt;img src='_images/100px.png_' /&gt;</p>
<p>&lt;img src="images/100px.png" /&gt;</p>
<p>&lt;img src="/images/100px.png" /&gt;</p>
<p>&lt;img src="../images/100px.png" /&gt;</p>
<p>&lt;img src="../../images/100px.png" /&gt;</p>
<p>&lt;img src="../../../images/100px.png" /&gt;</p>
<p>&lt;img src="http://example.com/images/100px.png" /&gt;</p>
<p>&lt;img src="aimages/100px.pnga" /&gt;</p>
<p>&lt;img src="1images/100px.png1" /&gt;</p>
<p>&lt;img src=".images/100px.png." /&gt;</p>
<p>&lt;img src="-images/100px.png-" /&gt;</p>
<p>&lt;img src="_images/100px.png_" /&gt;</p>
<p>background-image:url(images/100px.png);</p>
<p>background-image:url(/images/100px.png);</p>
<p>background-image:url(../images/100px.png);</p>
<p>background-image:url(../../images/100px.png);</p>
<p>background-image:url(../../../images/100px.png);</p>
<p>background-image:url(http://example.com/images/100px.png);</p>
<p>background-image:url(aimages/100px.pnga);</p>
<p>background-image:url(1images/100px.png1);</p>
<p>background-image:url(.images/100px.png.);</p>
<p>background-image:url(-images/100px.png-);</p>
<p>background-image:url(_images/100px.png_);</p>
<p>background-image:url('images/100px.png');</p>
<p>background-image:url('/images/100px.png');</p>
<p>background-image:url('../images/100px.png');</p>
<p>background-image:url('../../images/100px.png');</p>
<p>background-image:url('../../../images/100px.png');</p>
<p>background-image:url('http://example.com/images/100px.png');</p>
<p>background-image:url('aimages/100px.pnga');</p>
<p>background-image:url('1images/100px.png1');</p>
<p>background-image:url('.images/100px.png.');</p>
<p>background-image:url('-images/100px.png-');</p>
<p>background-image:url('_images/100px.png_');</p>
<p>background-image:url("images/100px.png");</p>
<p>background-image:url("/images/100px.png");</p>
<p>background-image:url("../images/100px.png");</p>
<p>background-image:url("../../images/100px.png");</p>
<p>background-image:url("../../../images/100px.png");</p>
<p>background-image:url("http://example.com/images/100px.png");</p>
<p>background-image:url("aimages/100px.pnga");</p>
<p>background-image:url("1images/100px.png1");</p>
<p>background-image:url(".images/100px.png.");</p>
<p>background-image:url("-images/100px.png-");</p>
<p>background-image:url("_images/100px.png_");</p>
<br /><br /><br />
<p>images/100px.gif</p>
<p>/images/100px.gif</p>
<p>../images/100px.gif</p>
<p>../../images/100px.gif</p>
<p>../../../images/100px.gif</p>
<p>http://example.com/images/100px.gif</p>
<p>aimages/100px.gifa</p>
<p>1images/100px.gif1</p>
<p>.images/100px.gif.</p>
<p>-images/100px.gif-</p>
<p>_images/100px.gif_</p>
<p>'images/100px.gif'</p>
<p>'/images/100px.gif'</p>
<p>'../images/100px.gif'</p>
<p>'../../images/100px.gif'</p>
<p>'../../../images/100px.gif'</p>
<p>'http://example.com/images/100px.gif'</p>
<p>'aimages/100px.gifa'</p>
<p>'1images/100px.gif1'</p>
<p>'.images/100px.gif.'</p>
<p>'-images/100px.gif-'</p>
<p>'_images/100px.gif_'</p>
<p>"images/100px.gif"</p>
<p>"/images/100px.gif"</p>
<p>"../images/100px.gif"</p>
<p>"../../images/100px.gif"</p>
<p>"../../../images/100px.gif"</p>
<p>"http://example.com/images/100px.gif"</p>
<p>"aimages/100px.gifa"</p>
<p>"1images/100px.gif1"</p>
<p>".images/100px.gif."</p>
<p>"-images/100px.gif-"</p>
<p>"_images/100px.gif_"</p>
<p>&lt;img src=images/100px.gif /&gt;</p>
<p>&lt;img src=/images/100px.gif /&gt;</p>
<p>&lt;img src=../images/100px.gif /&gt;</p>
<p>&lt;img src=../../images/100px.gif /&gt;</p>
<p>&lt;img src=../../../images/100px.gif /&gt;</p>
<p>&lt;img src=http://example.com/images/100px.gif /&gt;</p>
<p>&lt;img src=aimages/100px.gifa /&gt;</p>
<p>&lt;img src=1images/100px.gif1 /&gt;</p>
<p>&lt;img src=.images/100px.gif. /&gt;</p>
<p>&lt;img src=-images/100px.gif- /&gt;</p>
<p>&lt;img src=_images/100px.gif_ /&gt;</p>
<p>&lt;img src='images/100px.gif' /&gt;</p>
<p>&lt;img src='/images/100px.gif' /&gt;</p>
<p>&lt;img src='../images/100px.gif' /&gt;</p>
<p>&lt;img src='../../images/100px.gif' /&gt;</p>
<p>&lt;img src='../../../images/100px.gif' /&gt;</p>
<p>&lt;img src='http://example.com/images/100px.gif' /&gt;</p>
<p>&lt;img src='aimages/100px.gifa' /&gt;</p>
<p>&lt;img src='1images/100px.gif1' /&gt;</p>
<p>&lt;img src='.images/100px.gif.' /&gt;</p>
<p>&lt;img src='-images/100px.gif-' /&gt;</p>
<p>&lt;img src='_images/100px.gif_' /&gt;</p>
<p>&lt;img src="images/100px.gif" /&gt;</p>
<p>&lt;img src="/images/100px.gif" /&gt;</p>
<p>&lt;img src="../images/100px.gif" /&gt;</p>
<p>&lt;img src="../../images/100px.gif" /&gt;</p>
<p>&lt;img src="../../../images/100px.gif" /&gt;</p>
<p>&lt;img src="http://example.com/images/100px.gif" /&gt;</p>
<p>&lt;img src="aimages/100px.gifa" /&gt;</p>
<p>&lt;img src="1images/100px.gif1" /&gt;</p>
<p>&lt;img src=".images/100px.gif." /&gt;</p>
<p>&lt;img src="-images/100px.gif-" /&gt;</p>
<p>&lt;img src="_images/100px.gif_" /&gt;</p>
<p>background-image:url(images/100px.gif);</p>
<p>background-image:url(/images/100px.gif);</p>
<p>background-image:url(../images/100px.gif);</p>
<p>background-image:url(../../images/100px.gif);</p>
<p>background-image:url(../../../images/100px.gif);</p>
<p>background-image:url(http://example.com/images/100px.gif);</p>
<p>background-image:url(aimages/100px.gifa);</p>
<p>background-image:url(1images/100px.gif1);</p>
<p>background-image:url(.images/100px.gif.);</p>
<p>background-image:url(-images/100px.gif-);</p>
<p>background-image:url(_images/100px.gif_);</p>
<p>background-image:url('images/100px.gif');</p>
<p>background-image:url('/images/100px.gif');</p>
<p>background-image:url('../images/100px.gif');</p>
<p>background-image:url('../../images/100px.gif');</p>
<p>background-image:url('../../../images/100px.gif');</p>
<p>background-image:url('http://example.com/images/100px.gif');</p>
<p>background-image:url('aimages/100px.gifa');</p>
<p>background-image:url('1images/100px.gif1');</p>
<p>background-image:url('.images/100px.gif.');</p>
<p>background-image:url('-images/100px.gif-');</p>
<p>background-image:url('_images/100px.gif_');</p>
<p>background-image:url("images/100px.gif");</p>
<p>background-image:url("/images/100px.gif");</p>
<p>background-image:url("../images/100px.gif");</p>
<p>background-image:url("../../images/100px.gif");</p>
<p>background-image:url("../../../images/100px.gif");</p>
<p>background-image:url("http://example.com/images/100px.gif");</p>
<p>background-image:url("aimages/100px.gifa");</p>
<p>background-image:url("1images/100px.gif1");</p>
<p>background-image:url(".images/100px.gif.");</p>
<p>background-image:url("-images/100px.gif-");</p>
<p>background-image:url("_images/100px.gif_");</p>
<br /><br /><br />

View file

@ -0,0 +1,8 @@
function foo() {
var img = document.createElement('img');
img.src = '/images/100px.jpg';
var body = document.getElementsByTagName('body')[0];
body.insertBefore(img, body.firstChild);
}
window.onload = foo;

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<%= stylesheet_link_tag "site" %>
<%= javascript_include_tag "application" %>
<%= yield_content :head %>
</head>
<body class="<%= page_classes %>">
<div id="main" role="main">
<%= yield %>
</div>
</body>
</html>

View file

@ -0,0 +1,2 @@
<h2>Image url:</h2>
<img src="<%= image_path('100px.jpg') %>">

View file

@ -0,0 +1,6 @@
#main {
padding: 50px;
// Can't use image-url until compass problem is fixed: https://github.com/middleman/middleman/issues/283
// background-image: image-url('100px.jpg');
background-image: url('/images/100px.jpg');
}

View file

@ -0,0 +1,308 @@
<% content_for :head do %>
<title>The Middleman!</title>
<% end %>
<h2>Image url:</h2>
<p><%= image_path('100px.jpg') %></p>
<h2>Autogenerated tests:</h2>
<p>images/100px.jpg</p>
<p>/images/100px.jpg</p>
<p>../images/100px.jpg</p>
<p>../../images/100px.jpg</p>
<p>../../../images/100px.jpg</p>
<p>http://example.com/images/100px.jpg</p>
<p>aimages/100px.jpga</p>
<p>1images/100px.jpg1</p>
<p>.images/100px.jpg.</p>
<p>-images/100px.jpg-</p>
<p>_images/100px.jpg_</p>
<p>'images/100px.jpg'</p>
<p>'/images/100px.jpg'</p>
<p>'../images/100px.jpg'</p>
<p>'../../images/100px.jpg'</p>
<p>'../../../images/100px.jpg'</p>
<p>'http://example.com/images/100px.jpg'</p>
<p>'aimages/100px.jpga'</p>
<p>'1images/100px.jpg1'</p>
<p>'.images/100px.jpg.'</p>
<p>'-images/100px.jpg-'</p>
<p>'_images/100px.jpg_'</p>
<p>"images/100px.jpg"</p>
<p>"/images/100px.jpg"</p>
<p>"../images/100px.jpg"</p>
<p>"../../images/100px.jpg"</p>
<p>"../../../images/100px.jpg"</p>
<p>"http://example.com/images/100px.jpg"</p>
<p>"aimages/100px.jpga"</p>
<p>"1images/100px.jpg1"</p>
<p>".images/100px.jpg."</p>
<p>"-images/100px.jpg-"</p>
<p>"_images/100px.jpg_"</p>
<p>&lt;img src=images/100px.jpg /&gt;</p>
<p>&lt;img src=/images/100px.jpg /&gt;</p>
<p>&lt;img src=../images/100px.jpg /&gt;</p>
<p>&lt;img src=../../images/100px.jpg /&gt;</p>
<p>&lt;img src=../../../images/100px.jpg /&gt;</p>
<p>&lt;img src=http://example.com/images/100px.jpg /&gt;</p>
<p>&lt;img src=aimages/100px.jpga /&gt;</p>
<p>&lt;img src=1images/100px.jpg1 /&gt;</p>
<p>&lt;img src=.images/100px.jpg. /&gt;</p>
<p>&lt;img src=-images/100px.jpg- /&gt;</p>
<p>&lt;img src=_images/100px.jpg_ /&gt;</p>
<p>&lt;img src='images/100px.jpg' /&gt;</p>
<p>&lt;img src='/images/100px.jpg' /&gt;</p>
<p>&lt;img src='../images/100px.jpg' /&gt;</p>
<p>&lt;img src='../../images/100px.jpg' /&gt;</p>
<p>&lt;img src='../../../images/100px.jpg' /&gt;</p>
<p>&lt;img src='http://example.com/images/100px.jpg' /&gt;</p>
<p>&lt;img src='aimages/100px.jpga' /&gt;</p>
<p>&lt;img src='1images/100px.jpg1' /&gt;</p>
<p>&lt;img src='.images/100px.jpg.' /&gt;</p>
<p>&lt;img src='-images/100px.jpg-' /&gt;</p>
<p>&lt;img src='_images/100px.jpg_' /&gt;</p>
<p>&lt;img src="images/100px.jpg" /&gt;</p>
<p>&lt;img src="/images/100px.jpg" /&gt;</p>
<p>&lt;img src="../images/100px.jpg" /&gt;</p>
<p>&lt;img src="../../images/100px.jpg" /&gt;</p>
<p>&lt;img src="../../../images/100px.jpg" /&gt;</p>
<p>&lt;img src="http://example.com/images/100px.jpg" /&gt;</p>
<p>&lt;img src="aimages/100px.jpga" /&gt;</p>
<p>&lt;img src="1images/100px.jpg1" /&gt;</p>
<p>&lt;img src=".images/100px.jpg." /&gt;</p>
<p>&lt;img src="-images/100px.jpg-" /&gt;</p>
<p>&lt;img src="_images/100px.jpg_" /&gt;</p>
<p>background-image:url(images/100px.jpg);</p>
<p>background-image:url(/images/100px.jpg);</p>
<p>background-image:url(../images/100px.jpg);</p>
<p>background-image:url(../../images/100px.jpg);</p>
<p>background-image:url(../../../images/100px.jpg);</p>
<p>background-image:url(http://example.com/images/100px.jpg);</p>
<p>background-image:url(aimages/100px.jpga);</p>
<p>background-image:url(1images/100px.jpg1);</p>
<p>background-image:url(.images/100px.jpg.);</p>
<p>background-image:url(-images/100px.jpg-);</p>
<p>background-image:url(_images/100px.jpg_);</p>
<p>background-image:url('images/100px.jpg');</p>
<p>background-image:url('/images/100px.jpg');</p>
<p>background-image:url('../images/100px.jpg');</p>
<p>background-image:url('../../images/100px.jpg');</p>
<p>background-image:url('../../../images/100px.jpg');</p>
<p>background-image:url('http://example.com/images/100px.jpg');</p>
<p>background-image:url('aimages/100px.jpga');</p>
<p>background-image:url('1images/100px.jpg1');</p>
<p>background-image:url('.images/100px.jpg.');</p>
<p>background-image:url('-images/100px.jpg-');</p>
<p>background-image:url('_images/100px.jpg_');</p>
<p>background-image:url("images/100px.jpg");</p>
<p>background-image:url("/images/100px.jpg");</p>
<p>background-image:url("../images/100px.jpg");</p>
<p>background-image:url("../../images/100px.jpg");</p>
<p>background-image:url("../../../images/100px.jpg");</p>
<p>background-image:url("http://example.com/images/100px.jpg");</p>
<p>background-image:url("aimages/100px.jpga");</p>
<p>background-image:url("1images/100px.jpg1");</p>
<p>background-image:url(".images/100px.jpg.");</p>
<p>background-image:url("-images/100px.jpg-");</p>
<p>background-image:url("_images/100px.jpg_");</p>
<br /><br /><br />
<p>images/100px.png</p>
<p>/images/100px.png</p>
<p>../images/100px.png</p>
<p>../../images/100px.png</p>
<p>../../../images/100px.png</p>
<p>http://example.com/images/100px.png</p>
<p>aimages/100px.pnga</p>
<p>1images/100px.png1</p>
<p>.images/100px.png.</p>
<p>-images/100px.png-</p>
<p>_images/100px.png_</p>
<p>'images/100px.png'</p>
<p>'/images/100px.png'</p>
<p>'../images/100px.png'</p>
<p>'../../images/100px.png'</p>
<p>'../../../images/100px.png'</p>
<p>'http://example.com/images/100px.png'</p>
<p>'aimages/100px.pnga'</p>
<p>'1images/100px.png1'</p>
<p>'.images/100px.png.'</p>
<p>'-images/100px.png-'</p>
<p>'_images/100px.png_'</p>
<p>"images/100px.png"</p>
<p>"/images/100px.png"</p>
<p>"../images/100px.png"</p>
<p>"../../images/100px.png"</p>
<p>"../../../images/100px.png"</p>
<p>"http://example.com/images/100px.png"</p>
<p>"aimages/100px.pnga"</p>
<p>"1images/100px.png1"</p>
<p>".images/100px.png."</p>
<p>"-images/100px.png-"</p>
<p>"_images/100px.png_"</p>
<p>&lt;img src=images/100px.png /&gt;</p>
<p>&lt;img src=/images/100px.png /&gt;</p>
<p>&lt;img src=../images/100px.png /&gt;</p>
<p>&lt;img src=../../images/100px.png /&gt;</p>
<p>&lt;img src=../../../images/100px.png /&gt;</p>
<p>&lt;img src=http://example.com/images/100px.png /&gt;</p>
<p>&lt;img src=aimages/100px.pnga /&gt;</p>
<p>&lt;img src=1images/100px.png1 /&gt;</p>
<p>&lt;img src=.images/100px.png. /&gt;</p>
<p>&lt;img src=-images/100px.png- /&gt;</p>
<p>&lt;img src=_images/100px.png_ /&gt;</p>
<p>&lt;img src='images/100px.png' /&gt;</p>
<p>&lt;img src='/images/100px.png' /&gt;</p>
<p>&lt;img src='../images/100px.png' /&gt;</p>
<p>&lt;img src='../../images/100px.png' /&gt;</p>
<p>&lt;img src='../../../images/100px.png' /&gt;</p>
<p>&lt;img src='http://example.com/images/100px.png' /&gt;</p>
<p>&lt;img src='aimages/100px.pnga' /&gt;</p>
<p>&lt;img src='1images/100px.png1' /&gt;</p>
<p>&lt;img src='.images/100px.png.' /&gt;</p>
<p>&lt;img src='-images/100px.png-' /&gt;</p>
<p>&lt;img src='_images/100px.png_' /&gt;</p>
<p>&lt;img src="images/100px.png" /&gt;</p>
<p>&lt;img src="/images/100px.png" /&gt;</p>
<p>&lt;img src="../images/100px.png" /&gt;</p>
<p>&lt;img src="../../images/100px.png" /&gt;</p>
<p>&lt;img src="../../../images/100px.png" /&gt;</p>
<p>&lt;img src="http://example.com/images/100px.png" /&gt;</p>
<p>&lt;img src="aimages/100px.pnga" /&gt;</p>
<p>&lt;img src="1images/100px.png1" /&gt;</p>
<p>&lt;img src=".images/100px.png." /&gt;</p>
<p>&lt;img src="-images/100px.png-" /&gt;</p>
<p>&lt;img src="_images/100px.png_" /&gt;</p>
<p>background-image:url(images/100px.png);</p>
<p>background-image:url(/images/100px.png);</p>
<p>background-image:url(../images/100px.png);</p>
<p>background-image:url(../../images/100px.png);</p>
<p>background-image:url(../../../images/100px.png);</p>
<p>background-image:url(http://example.com/images/100px.png);</p>
<p>background-image:url(aimages/100px.pnga);</p>
<p>background-image:url(1images/100px.png1);</p>
<p>background-image:url(.images/100px.png.);</p>
<p>background-image:url(-images/100px.png-);</p>
<p>background-image:url(_images/100px.png_);</p>
<p>background-image:url('images/100px.png');</p>
<p>background-image:url('/images/100px.png');</p>
<p>background-image:url('../images/100px.png');</p>
<p>background-image:url('../../images/100px.png');</p>
<p>background-image:url('../../../images/100px.png');</p>
<p>background-image:url('http://example.com/images/100px.png');</p>
<p>background-image:url('aimages/100px.pnga');</p>
<p>background-image:url('1images/100px.png1');</p>
<p>background-image:url('.images/100px.png.');</p>
<p>background-image:url('-images/100px.png-');</p>
<p>background-image:url('_images/100px.png_');</p>
<p>background-image:url("images/100px.png");</p>
<p>background-image:url("/images/100px.png");</p>
<p>background-image:url("../images/100px.png");</p>
<p>background-image:url("../../images/100px.png");</p>
<p>background-image:url("../../../images/100px.png");</p>
<p>background-image:url("http://example.com/images/100px.png");</p>
<p>background-image:url("aimages/100px.pnga");</p>
<p>background-image:url("1images/100px.png1");</p>
<p>background-image:url(".images/100px.png.");</p>
<p>background-image:url("-images/100px.png-");</p>
<p>background-image:url("_images/100px.png_");</p>
<br /><br /><br />
<p>images/100px.gif</p>
<p>/images/100px.gif</p>
<p>../images/100px.gif</p>
<p>../../images/100px.gif</p>
<p>../../../images/100px.gif</p>
<p>http://example.com/images/100px.gif</p>
<p>aimages/100px.gifa</p>
<p>1images/100px.gif1</p>
<p>.images/100px.gif.</p>
<p>-images/100px.gif-</p>
<p>_images/100px.gif_</p>
<p>'images/100px.gif'</p>
<p>'/images/100px.gif'</p>
<p>'../images/100px.gif'</p>
<p>'../../images/100px.gif'</p>
<p>'../../../images/100px.gif'</p>
<p>'http://example.com/images/100px.gif'</p>
<p>'aimages/100px.gifa'</p>
<p>'1images/100px.gif1'</p>
<p>'.images/100px.gif.'</p>
<p>'-images/100px.gif-'</p>
<p>'_images/100px.gif_'</p>
<p>"images/100px.gif"</p>
<p>"/images/100px.gif"</p>
<p>"../images/100px.gif"</p>
<p>"../../images/100px.gif"</p>
<p>"../../../images/100px.gif"</p>
<p>"http://example.com/images/100px.gif"</p>
<p>"aimages/100px.gifa"</p>
<p>"1images/100px.gif1"</p>
<p>".images/100px.gif."</p>
<p>"-images/100px.gif-"</p>
<p>"_images/100px.gif_"</p>
<p>&lt;img src=images/100px.gif /&gt;</p>
<p>&lt;img src=/images/100px.gif /&gt;</p>
<p>&lt;img src=../images/100px.gif /&gt;</p>
<p>&lt;img src=../../images/100px.gif /&gt;</p>
<p>&lt;img src=../../../images/100px.gif /&gt;</p>
<p>&lt;img src=http://example.com/images/100px.gif /&gt;</p>
<p>&lt;img src=aimages/100px.gifa /&gt;</p>
<p>&lt;img src=1images/100px.gif1 /&gt;</p>
<p>&lt;img src=.images/100px.gif. /&gt;</p>
<p>&lt;img src=-images/100px.gif- /&gt;</p>
<p>&lt;img src=_images/100px.gif_ /&gt;</p>
<p>&lt;img src='images/100px.gif' /&gt;</p>
<p>&lt;img src='/images/100px.gif' /&gt;</p>
<p>&lt;img src='../images/100px.gif' /&gt;</p>
<p>&lt;img src='../../images/100px.gif' /&gt;</p>
<p>&lt;img src='../../../images/100px.gif' /&gt;</p>
<p>&lt;img src='http://example.com/images/100px.gif' /&gt;</p>
<p>&lt;img src='aimages/100px.gifa' /&gt;</p>
<p>&lt;img src='1images/100px.gif1' /&gt;</p>
<p>&lt;img src='.images/100px.gif.' /&gt;</p>
<p>&lt;img src='-images/100px.gif-' /&gt;</p>
<p>&lt;img src='_images/100px.gif_' /&gt;</p>
<p>&lt;img src="images/100px.gif" /&gt;</p>
<p>&lt;img src="/images/100px.gif" /&gt;</p>
<p>&lt;img src="../images/100px.gif" /&gt;</p>
<p>&lt;img src="../../images/100px.gif" /&gt;</p>
<p>&lt;img src="../../../images/100px.gif" /&gt;</p>
<p>&lt;img src="http://example.com/images/100px.gif" /&gt;</p>
<p>&lt;img src="aimages/100px.gifa" /&gt;</p>
<p>&lt;img src="1images/100px.gif1" /&gt;</p>
<p>&lt;img src=".images/100px.gif." /&gt;</p>
<p>&lt;img src="-images/100px.gif-" /&gt;</p>
<p>&lt;img src="_images/100px.gif_" /&gt;</p>
<p>background-image:url(images/100px.gif);</p>
<p>background-image:url(/images/100px.gif);</p>
<p>background-image:url(../images/100px.gif);</p>
<p>background-image:url(../../images/100px.gif);</p>
<p>background-image:url(../../../images/100px.gif);</p>
<p>background-image:url(http://example.com/images/100px.gif);</p>
<p>background-image:url(aimages/100px.gifa);</p>
<p>background-image:url(1images/100px.gif1);</p>
<p>background-image:url(.images/100px.gif.);</p>
<p>background-image:url(-images/100px.gif-);</p>
<p>background-image:url(_images/100px.gif_);</p>
<p>background-image:url('images/100px.gif');</p>
<p>background-image:url('/images/100px.gif');</p>
<p>background-image:url('../images/100px.gif');</p>
<p>background-image:url('../../images/100px.gif');</p>
<p>background-image:url('../../../images/100px.gif');</p>
<p>background-image:url('http://example.com/images/100px.gif');</p>
<p>background-image:url('aimages/100px.gifa');</p>
<p>background-image:url('1images/100px.gif1');</p>
<p>background-image:url('.images/100px.gif.');</p>
<p>background-image:url('-images/100px.gif-');</p>
<p>background-image:url('_images/100px.gif_');</p>
<p>background-image:url("images/100px.gif");</p>
<p>background-image:url("/images/100px.gif");</p>
<p>background-image:url("../images/100px.gif");</p>
<p>background-image:url("../../images/100px.gif");</p>
<p>background-image:url("../../../images/100px.gif");</p>
<p>background-image:url("http://example.com/images/100px.gif");</p>
<p>background-image:url("aimages/100px.gifa");</p>
<p>background-image:url("1images/100px.gif1");</p>
<p>background-image:url(".images/100px.gif.");</p>
<p>background-image:url("-images/100px.gif-");</p>
<p>background-image:url("_images/100px.gif_");</p>
<br /><br /><br />

View file

@ -35,6 +35,10 @@ module Middleman
# browser caches failing to update to your new content. # browser caches failing to update to your new content.
autoload :CacheBuster, "middleman-more/extensions/cache_buster" autoload :CacheBuster, "middleman-more/extensions/cache_buster"
# AssetHash appends a hash of the file contents to the assets filename
# to avoid browser caches failing to update to your new content.
autoload :AssetHash, "middleman-more/extensions/asset_hash"
# MinifyCss uses the YUI compressor to shrink CSS files # MinifyCss uses the YUI compressor to shrink CSS files
autoload :MinifyCss, "middleman-more/extensions/minify_css" autoload :MinifyCss, "middleman-more/extensions/minify_css"
@ -65,4 +69,6 @@ module Middleman
::Middleman::Extensions::MinifyJavascript } ::Middleman::Extensions::MinifyJavascript }
Extensions.register(:relative_assets) { Extensions.register(:relative_assets) {
::Middleman::Extensions::RelativeAssets } ::Middleman::Extensions::RelativeAssets }
end Middleman::Extensions.register(:asset_hash) {
Middleman::Extensions::AssetHash }
end

View file

@ -0,0 +1,97 @@
require 'digest/sha1'
module Middleman::Extensions
module AssetHash
class << self
def registered(app, options)
exts = options[:exts] || %w(.ico .manifest .jpg .jpeg .png .gif .js .css)
app.after_configuration do
# Register a reroute transform that adds .gz to asset paths
sitemap.reroute do |destination, page|
if exts.include? page.ext
app.cache.fetch(:asset_hash, page.path) do
digest = Digest::SHA1.file(page.source_file).hexdigest[0..7]
destination.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
end
else
destination
end
end
use Middleware, :exts => exts, :middleman_app => self
end
end
alias :included :registered
end
class Middleware
def initialize(app, options={})
@rack_app = app
@exts = options[:exts]
@exts_regex_text = @exts.map {|e| Regexp.escape(e) }.join('|')
@middleman_app = options[:middleman_app]
end
def call(env)
status, headers, response = @rack_app.call(env)
path = @middleman_app.full_path(env["PATH_INFO"])
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
if body
# TODO: This regex will change some paths in plan HTML (not in a tag) - is that OK?
body.gsub! /([=\'\"\(]\s*)([^\s\'\"\)]+(#{@exts_regex_text}))/ do |match|
asset_path = $2
relative_path = Pathname.new(asset_path).relative?
asset_path = dirpath.join(asset_path).to_s if relative_path
if @middleman_app.sitemap.exists? asset_path
asset_page = @middleman_app.sitemap.page asset_path
replacement_path = "/#{asset_page.destination_path}"
replacement_path = Pathname.new(replacement_path).relative_path_from(dirpath).to_s if relative_path
"#{$1}#{replacement_path}"
else
match
end
end
status, headers, response = Rack::Response.new(body, status, headers).finish
end
end
[status, headers, response]
end
end
end
register :asset_hash, AssetHash
end
# =================Temp Generate Test data==============================
# ["jpg", "png", "gif"].each do |ext|
# [["<p>", "</p>"], ["<p><img src=", " /></p>"], ["<p>background-image:url(", ");</p>"]].each do |outer|
# [["",""], ["'", "'"], ['"','"']].each do |inner|
# [["", ""], ["/", ""], ["../", ""], ["../../", ""], ["../../../", ""], ["http://example.com/", ""], ["a","a"], ["1","1"], [".", "."], ["-","-"], ["_","_"]].each do |path_parts|
# name = 'images/100px.'
# puts outer[0] + inner[0] + path_parts[0] + name + ext + path_parts[1] + inner[1] + outer[1]
# end
# end
# end
# puts "<br /><br /><br />"
# end