Disclaimer: sprockets in general is phased out in the Rails community, still some people need the fix ... I needed a fix today.
Issue: I have an old gem that reference an relative image in the CSS background-image: url("icon.png"))
which once compile it become:
Sprockets 3:
background-image: url("icon.png"))
(it's a relative URL)Sprockets 4:
background-image: url("/icon.png"))
(the/
means root URL, eghttp://example.org/icon.png
)With the fix below:
background-image: url("./icon.png"))
(./
is also a relative URL)
Notes about relative URL:
If the CSS file is
http://example.com/application.css
- then the
icon.png
is also at the root:http://example.com/icon.png
- then the
If the CSS file is in a gem (for me it was CKeditor), the CSS file is
http://example.com/assets/ckeditor/skins/moono-lisa/editor.css
- then the
icon.png
is resolved ashttp://example.com/assets/ckeditor/skins/moono-lisa/icon.png
- then the
# config/initializers/sprockets.rb
# Issue exists: https://github.com/rails/sprockets-rails/issues/507
# Fix from PR: https://github.com/rails/sprockets-rails/pull/511
# It will not get merge as Sprockets is phased out.
module Sprockets
module Rails
# Resolve assets referenced in CSS `url()` calls and replace them with the digested paths
class AssetUrlProcessor
REGEX = /url\(\s*["']?(?!(?:\#|data|http))(?<relativeToCurrentDir>\.\/)?(?<path>[^"'\s)]+)\s*["']?\)/
def self.call(input)
context = input[:environment].context_class.new(input)
data = input[:data].gsub(REGEX) do |_match|
path = Regexp.last_match[:path]
# Prevent non-digest relative path from being converted to root absolute path
orig_path = path
path = context.asset_path(path)
path = (path == "/#{orig_path}") ? ".#{path}" : path
"url(#{path})"
end
context.metadata.merge(data: data)
end
end
end
end
Caveat: the original file did not change therefore the digest did not either, until the browser invalid the the cache and download the new CSS, users will have the old CSS cached by the browser
Please share and comment on how I can write it better.