Skip to content

Commit

Permalink
first draft of relative URL rewriting
Browse files Browse the repository at this point in the history
  • Loading branch information
jashkenas committed Nov 24, 2009
1 parent 6014467 commit 8e264a3
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 23 deletions.
2 changes: 1 addition & 1 deletion index.html
Expand Up @@ -250,7 +250,7 @@ <h2 id="configuration">Configuration</h2>
The URL at which packaged assets are cached and made available.
Defaults to <b>assets</b>, but if you already have an existing
AssetsController with a different purpose, you could change it to, say,
<b>packages</b>.
<b>packages</b>. <i>(Single directory names only, please.)</i>
</td>
</tr>
</table>
Expand Down
8 changes: 5 additions & 3 deletions lib/jammit.rb
Expand Up @@ -4,11 +4,13 @@
# to all of the configuration options.
module Jammit

VERSION = "0.2.7"
VERSION = "0.2.7"

ROOT = File.expand_path(File.dirname(__FILE__) + '/..')
ROOT = File.expand_path(File.dirname(__FILE__) + '/..')

ASSET_ROOT = defined?(RAILS_ROOT) ? RAILS_ROOT : "."
ASSET_ROOT = File.expand_path(defined?(RAILS_ROOT) ? RAILS_ROOT : ".")

PUBLIC_ROOT = "#{ASSET_ROOT}/public"

DEFAULT_CONFIG_PATH = "#{ASSET_ROOT}/config/assets.yml"

Expand Down
52 changes: 36 additions & 16 deletions lib/jammit/compressor.rb
Expand Up @@ -17,8 +17,9 @@ class Compressor
'.tiff' => 'image/tiff'
}

# Detect all image URLs that are inside of an "embed" folder.
IMAGE_DETECTOR = /url\(['"]?([^\s)]*embed\/[^\s)]+\.(png|jpg|jpeg|gif|tif|tiff))['"]?\)/

IMAGE_DETECTOR = /url\(['"]?([^\s)]+\.(png|jpg|jpeg|gif|tif|tiff))['"]?\)/
IMAGE_EMBED = /[\A\/]embed\//
IMAGE_REPLACER = /url\(__EMBED__([^\s)]+)\)/

# MHTML file constants.
Expand Down Expand Up @@ -57,11 +58,13 @@ def compress_js(paths)
# :datauri or :mhtml variant, post-processes the result to embed
# referenced images.
def compress_css(paths, variant=nil, asset_url=nil)
return @css_compressor.compress(concatenate(paths)) if variant.nil?
compressed_css = @css_compressor.compress(concatenate_and_tag_images(paths))
return with_data_uris(compressed_css) if variant == :datauri
return with_mhtml(compressed_css, asset_url) if variant == :mhtml
raise PackageNotFound, "\"#{variant}\" is not a valid stylesheet variant"
compressed_css = @css_compressor.compress(concatenate_and_tag_images(paths, variant))
case variant
when nil then return compressed_css
when :datauri then return with_data_uris(compressed_css)
when :mhtml then return with_mhtml(compressed_css, asset_url)
else raise PackageNotFound, "\"#{variant}\" is not a valid stylesheet variant"
end
end

# Compiles a single JST file by writing out a javascript that adds
Expand All @@ -86,11 +89,11 @@ def compile_jst(paths)
# expand the paths before contatenating the CSS together and losing the
# location of the original stylesheet path. Validate the images while we're
# at it.
def concatenate_and_tag_images(paths)
def concatenate_and_tag_images(paths, variant=nil)
stylesheets = [paths].flatten.map do |css_path|
File.read(css_path).gsub(IMAGE_DETECTOR) do |url|
image_path = public_path($1, css_path)
valid_image(image_path) ? "url(__EMBED__#{image_path})" : url
new_path = rewrite_image_path(Pathname.new($1), Pathname.new(File.expand_path(css_path)), !!variant)
"url(#{new_path})"
end
end
stylesheets.join("\n")
Expand Down Expand Up @@ -120,18 +123,35 @@ def with_mhtml(css, asset_url)
[MHTML_START, mhtml, MHTML_END, css].flatten.join('')
end

# Return a rewritten image URL for a new stylesheet -- the image should
# be tagged for embedding if embeddable, and referenced at the correct level
# if relative.
def rewrite_image_path(image_path, css_path, embed=false)
public_path = absolute_path(image_path, css_path)
return "__EMBED__#{public_path}" if embed && embeddable?(public_path)
image_path.relative? ? relative_path(public_path) : image_path.to_s
end

# Get the site-absolute public path for an image file path that may or may
# not be relative, given the path of the stylesheet that contains it.
def public_path(image_path, css_path)
image_path, css_path = Pathname.new(image_path), Pathname.new(css_path)
(image_path.absolute? ? Pathname.new("#{ASSET_ROOT}/public#{image_path}") : css_path.dirname + image_path).cleanpath
def absolute_path(image_pathname, css_pathname)
(image_pathname.absolute? ?
Pathname.new(File.join(PUBLIC_ROOT, image_pathname)) :
css_pathname.dirname + image_pathname).cleanpath
end

# CSS images that are referenced by relative paths, and are *not* being
# embedded, must be rewritten relative to the newly-merged stylesheet path.
def relative_path(absolute_path)
File.join('../', absolute_path.sub(PUBLIC_ROOT, ''))
end

# An image is valid if it exists, and is less than 32K.
# An image is valid for embedding if it exists, is less than 32K, and is
# stored somewhere inside of a folder named "embed".
# IE does not support Data-URIs larger than 32K, and you probably shouldn't
# be embedding images that large in any case.
def valid_image(image_path)
image_path.exist? && image_path.size < 32.kilobytes
def embeddable?(image_path)
image_path.to_s.match(IMAGE_EMBED) && image_path.exist? && image_path.size < 32.kilobytes
end

# Return the Base64-encoded contents of an image on a single line.
Expand Down
3 changes: 2 additions & 1 deletion lib/jammit/controller.rb
Expand Up @@ -9,7 +9,7 @@ class Controller < ActionController::Base

SUFFIX_STRIPPER = /-(datauri|mhtml)\Z/

NOT_FOUND_PATH = "#{ASSET_ROOT}/public/404.html"
NOT_FOUND_PATH = "#{PUBLIC_ROOT}/404.html"

after_filter :cache_package if perform_caching

Expand Down Expand Up @@ -82,6 +82,7 @@ def package_not_found

end

# Make the Jammit::Controller available to Rails as a top-level controller.
::JammitController = Jammit::Controller

if RAILS_ENV == 'development'
Expand Down
2 changes: 1 addition & 1 deletion lib/jammit/packager.rb
Expand Up @@ -37,7 +37,7 @@ def initialize
# Unless forced, will only rebuild assets whose source files have been
# changed since their last package build.
def precache_all(output_dir=nil, base_url=nil)
output_dir ||= "#{ASSET_ROOT}/public/#{Jammit.package_path}"
output_dir ||= File.join(PUBLIC_ROOT, Jammit.package_path)
cacheable(:js, output_dir).each {|p| cache(p, 'js', pack_javascripts(p), output_dir) }
cacheable(:jst, output_dir).each {|p| cache(p, 'jst', pack_templates(p), output_dir) }
cacheable(:css, output_dir).each do |p|
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/jammed/test.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8e264a3

Please sign in to comment.