Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Propagate digested paths for asset files from v3 to v2 #499

Draft
wants to merge 1 commit into
base: 2.x
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -117,6 +117,9 @@ config.assets.configure do |env|
end
```

**`config.assets.resolve_assets_in_css_urls`**

When this option is enabled, sprockets-rails will register a CSS postprocessor to resolve assets referenced in [`url()`](https://developer.mozilla.org/en-US/docs/Web/CSS/url()) function calls and replace them with the digested paths. Defaults to `true`.

## Complementary plugins

Expand Down
22 changes: 22 additions & 0 deletions lib/sprockets/rails/asset_url_processor.rb
@@ -0,0 +1,22 @@
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]
begin
"url(#{context.asset_path(path)})"
rescue => e
puts "AssetUrlProcessor: Error processing asset |#{path}|: #{e.class.name}: #{e.message}"
"url(#{path})"
end
end

context.metadata.merge(data: data)
end
end
end
end
8 changes: 8 additions & 0 deletions lib/sprockets/railtie.rb
Expand Up @@ -5,6 +5,7 @@
require 'sprockets'
require 'sprockets/rails/helper'
require 'sprockets/rails/version'
require 'sprockets/rails/asset_url_processor'

module Rails
class Application
Expand Down Expand Up @@ -77,6 +78,13 @@ def configure(&block)
config.assets.debug = false
config.assets.compile = true
config.assets.digest = false
config.assets.resolve_assets_in_css_urls = true

initializer :asset_url_processor do |app|
if app.config.assets.resolve_assets_in_css_urls
Sprockets.register_postprocessor "text/css", ::Sprockets::Rails::AssetUrlProcessor
end
end

rake_tasks do |app|
require 'sprockets/rails/task'
Expand Down
70 changes: 70 additions & 0 deletions test/test_asset_url_processor.rb
@@ -0,0 +1,70 @@
require 'minitest/autorun'
require 'sprockets/railtie'


Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)
class TestAssetUrlProcessor < Minitest::Test
FIXTURES_PATH = File.expand_path("../fixtures", __FILE__)

def setup
@env = Sprockets::Environment.new
@env.append_path FIXTURES_PATH
@env.context_class.class_eval do
include ::Sprockets::Rails::Context
end
@env.context_class.digest_assets = true

@logo_digest = @env["logo.png"].etag
@logo_uri = @env["logo.png"].uri
end

def test_basic
input = { environment: @env, data: 'background: url(logo.png);', filename: 'url2.css', metadata: {} }
output = Sprockets::Rails::AssetUrlProcessor.call(input)
assert_equal("background: url(/logo-#{@logo_digest}.png);", output[:data])
end

def test_spaces
input = { environment: @env, data: 'background: url( logo.png );', filename: 'url2.css', metadata: {} }
output = Sprockets::Rails::AssetUrlProcessor.call(input)
assert_equal("background: url(/logo-#{@logo_digest}.png);", output[:data])
end

def test_single_quote
input = { environment: @env, data: "background: url('logo.png');", filename: 'url2.css', metadata: {} }
output = Sprockets::Rails::AssetUrlProcessor.call(input)
assert_equal("background: url(/logo-#{@logo_digest}.png);", output[:data])
end

def test_double_quote
input = { environment: @env, data: 'background: url("logo.png");', filename: 'url2.css', metadata: {} }
output = Sprockets::Rails::AssetUrlProcessor.call(input)
assert_equal("background: url(/logo-#{@logo_digest}.png);", output[:data])
end

def test_dependencies_are_tracked
input = { environment: @env, data: 'background: url(logo.png);', filename: 'url2.css', metadata: {} }
output = Sprockets::Rails::AssetUrlProcessor.call(input)
assert_equal(1, output[:links].size)
assert_equal(@logo_uri, output[:links].first)
end

def test_relative
input = { environment: @env, data: 'background: url(./logo.png);', filename: 'url2.css', metadata: {} }
output = Sprockets::Rails::AssetUrlProcessor.call(input)
assert_equal("background: url(/logo-#{@logo_digest}.png);", output[:data])
end

def test_subdirectory
input = { environment: @env, data: "background: url('jquery/jquery.js');", filename: 'url2.css', metadata: {} }
output = Sprockets::Rails::AssetUrlProcessor.call(input)
jquery_digest = 'c6910e1db4a5ed4905be728ab786471e81565f4a9d544734b199f3790de9f9a3'
assert_equal("background: url(/jquery/jquery-#{jquery_digest}.js);", output[:data])
end

def test_protocol_relative_paths
input = { environment: @env, data: "background: url(//assets.example.com/assets/fontawesome-webfont-82ff0fe46a6f60e0ab3c4a9891a0ae0a1f7b7e84c625f55358379177a2dcb202.eot);", filename: 'url2.css', metadata: {} }
output = Sprockets::Rails::AssetUrlProcessor.call(input)
assert_equal("background: url(//assets.example.com/assets/fontawesome-webfont-82ff0fe46a6f60e0ab3c4a9891a0ae0a1f7b7e84c625f55358379177a2dcb202.eot);", output[:data])
end
end
17 changes: 17 additions & 0 deletions test/test_railtie.rb
Expand Up @@ -256,4 +256,21 @@ def test_manifest_path_respects_rails_public_path
assert_match %r{test_public/assets$}, manifest.dir
end
end

def test_resolve_assets_in_css_urls_defaults_to_true
app.initialize!

assert_equal true, app.config.assets.resolve_assets_in_css_urls
assert_includes Sprockets.postprocessors['text/css'], Sprockets::Rails::AssetUrlProcessor
end

def test_resolve_assets_in_css_urls_when_false_avoids_registering_postprocessor
app.configure do
config.assets.resolve_assets_in_css_urls = false
end
app.initialize!

assert_equal false, app.config.assets.resolve_assets_in_css_urls
refute_includes Sprockets.postprocessors['text/css'], Sprockets::Rails::AssetUrlProcessor
end
end