From 95278a4a8a63b9d189c9116c0d1b84e760f05742 Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Mon, 7 Feb 2022 10:49:36 +0000 Subject: [PATCH 1/3] Split js sourcemapping into base & js classes --- .../rails/base_sourcemapping_url_processor.rb | 47 +++++++++++++++++++ .../rails/sourcemapping_url_processor.rb | 38 +-------------- lib/sprockets/railtie.rb | 1 + 3 files changed, 49 insertions(+), 37 deletions(-) create mode 100644 lib/sprockets/rails/base_sourcemapping_url_processor.rb diff --git a/lib/sprockets/rails/base_sourcemapping_url_processor.rb b/lib/sprockets/rails/base_sourcemapping_url_processor.rb new file mode 100644 index 00000000..dd5dcab1 --- /dev/null +++ b/lib/sprockets/rails/base_sourcemapping_url_processor.rb @@ -0,0 +1,47 @@ +module Sprockets + module Rails + class BaseSourcemappingUrlProcessor + class << self + def call(input) + env = input[:environment] + context = env.context_class.new(input) + data = input[:data].gsub(self::REGEX) do |_match| + sourcemap_logical_path = combine_sourcemap_logical_path(sourcefile: input[:name], sourcemap: $1) + + begin + resolved_sourcemap_comment(sourcemap_logical_path, context: context) + rescue Sprockets::FileNotFound + removed_sourcemap_comment(sourcemap_logical_path, filename: input[:filename], env: env) + end + end + + { data: data } + end + + private + def combine_sourcemap_logical_path(sourcefile:, sourcemap:) + if (parts = sourcefile.split("/")).many? + parts[0..-2].append(sourcemap).join("/") + else + sourcemap + end + end + + def sourcemap_asset_path(sourcemap_logical_path, context:) + # FIXME: Work-around for bug where if the sourcemap is nested two levels deep, it'll resolve as the source file + # that's being mapped, rather than the map itself. So context.resolve("a/b/c.js.map") will return "c.js?" + if context.resolve(sourcemap_logical_path) =~ /\.map/ + context.asset_path(sourcemap_logical_path) + else + raise Sprockets::FileNotFound, "Failed to resolve source map asset due to nesting depth" + end + end + + def removed_sourcemap_comment(sourcemap_logical_path, filename:, env:) + env.logger.warn "Removed sourceMappingURL comment for missing asset '#{sourcemap_logical_path}' from #{filename}" + nil + end + end + end + end +end diff --git a/lib/sprockets/rails/sourcemapping_url_processor.rb b/lib/sprockets/rails/sourcemapping_url_processor.rb index fe8a29cc..ed069d35 100644 --- a/lib/sprockets/rails/sourcemapping_url_processor.rb +++ b/lib/sprockets/rails/sourcemapping_url_processor.rb @@ -1,53 +1,17 @@ module Sprockets module Rails # Rewrites source mapping urls with the digested paths and protect against semicolon appending with a dummy comment line - class SourcemappingUrlProcessor + class SourcemappingUrlProcessor < BaseSourcemappingUrlProcessor REGEX = /\/\/# sourceMappingURL=(.*\.map)/ class << self - def call(input) - env = input[:environment] - context = env.context_class.new(input) - data = input[:data].gsub(REGEX) do |_match| - sourcemap_logical_path = combine_sourcemap_logical_path(sourcefile: input[:name], sourcemap: $1) - - begin - resolved_sourcemap_comment(sourcemap_logical_path, context: context) - rescue Sprockets::FileNotFound - removed_sourcemap_comment(sourcemap_logical_path, filename: input[:filename], env: env) - end - end - - { data: data } - end private - def combine_sourcemap_logical_path(sourcefile:, sourcemap:) - if (parts = sourcefile.split("/")).many? - parts[0..-2].append(sourcemap).join("/") - else - sourcemap - end - end def resolved_sourcemap_comment(sourcemap_logical_path, context:) "//# sourceMappingURL=#{sourcemap_asset_path(sourcemap_logical_path, context: context)}\n//!\n" end - def sourcemap_asset_path(sourcemap_logical_path, context:) - # FIXME: Work-around for bug where if the sourcemap is nested two levels deep, it'll resolve as the source file - # that's being mapped, rather than the map itself. So context.resolve("a/b/c.js.map") will return "c.js?" - if context.resolve(sourcemap_logical_path) =~ /\.map/ - context.asset_path(sourcemap_logical_path) - else - raise Sprockets::FileNotFound, "Failed to resolve source map asset due to nesting depth" - end - end - - def removed_sourcemap_comment(sourcemap_logical_path, filename:, env:) - env.logger.warn "Removed sourceMappingURL comment for missing asset '#{sourcemap_logical_path}' from #{filename}" - nil - end end end end diff --git a/lib/sprockets/railtie.rb b/lib/sprockets/railtie.rb index 1ebfaa61..4d2a40c6 100644 --- a/lib/sprockets/railtie.rb +++ b/lib/sprockets/railtie.rb @@ -6,6 +6,7 @@ require 'sprockets' require 'sprockets/rails/asset_url_processor' +require 'sprockets/rails/base_sourcemapping_url_processor' require 'sprockets/rails/sourcemapping_url_processor' require 'sprockets/rails/context' require 'sprockets/rails/helper' From ce79c83e6195dfdda6b04c689f596ccd5c29b8d0 Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Mon, 7 Feb 2022 10:54:05 +0000 Subject: [PATCH 2/3] Add sourcemap url processor for css --- .../rails/css_sourcemapping_url_processor.rb | 18 +++++++ test/test_css_sourcemapping_url_processor.rb | 49 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 lib/sprockets/rails/css_sourcemapping_url_processor.rb create mode 100644 test/test_css_sourcemapping_url_processor.rb diff --git a/lib/sprockets/rails/css_sourcemapping_url_processor.rb b/lib/sprockets/rails/css_sourcemapping_url_processor.rb new file mode 100644 index 00000000..7030a612 --- /dev/null +++ b/lib/sprockets/rails/css_sourcemapping_url_processor.rb @@ -0,0 +1,18 @@ +module Sprockets + module Rails + # Rewrites source mapping urls with the digested paths and protect against semicolon appending with a dummy comment line + class CssSourcemappingUrlProcessor < BaseSourcemappingUrlProcessor + REGEX = %r{/\*# sourceMappingURL=(.*\.map)\s*\*/} + + class << self + + private + + def resolved_sourcemap_comment(sourcemap_logical_path, context:) + "/*# sourceMappingURL=#{sourcemap_asset_path(sourcemap_logical_path, context: context)} */\n" + end + + end + end + end +end diff --git a/test/test_css_sourcemapping_url_processor.rb b/test/test_css_sourcemapping_url_processor.rb new file mode 100644 index 00000000..408761c5 --- /dev/null +++ b/test/test_css_sourcemapping_url_processor.rb @@ -0,0 +1,49 @@ +require 'minitest/autorun' +require 'sprockets/railtie' + +Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) +class TestCssSourceMappingUrlProcessor < Minitest::Test + def setup + @env = Sprockets::Environment.new + end + + def test_successful + @env.context_class.class_eval do + def resolve(path, **kargs) + "/assets/mapped.css.map" + end + + def asset_path(path, options = {}) + "/assets/mapped-HEXGOESHERE.css.map" + end + end + + input = { environment: @env, data: "div {\ndisplay: none;\n}\n/*# sourceMappingURL=mapped.css.map */", name: 'mapped', filename: 'mapped.css', metadata: {} } + output = Sprockets::Rails::CssSourcemappingUrlProcessor.call(input) + assert_equal({ data: "div {\ndisplay: none;\n}\n/*# sourceMappingURL=/assets/mapped-HEXGOESHERE.css.map */\n" }, output) + end + + def test_resolving_erroneously_without_map_extension + @env.context_class.class_eval do + def resolve(path, **kargs) + "/assets/mapped.css" + end + end + + input = { environment: @env, data: "div {\ndisplay: none;\n}\n/*# sourceMappingURL=mapped.css.map */", name: 'mapped', filename: 'mapped.css', metadata: {} } + output = Sprockets::Rails::CssSourcemappingUrlProcessor.call(input) + assert_equal({ data: "div {\ndisplay: none;\n}\n" }, output) + end + + def test_missing + @env.context_class.class_eval do + def resolve(path, **kargs) + raise Sprockets::FileNotFound + end + end + + input = { environment: @env, data: "div {\ndisplay: none;\n}\n/*# sourceMappingURL=mappedNOT.css.map */", name: 'mapped', filename: 'mapped.css', metadata: {} } + output = Sprockets::Rails::CssSourcemappingUrlProcessor.call(input) + assert_equal({ data: "div {\ndisplay: none;\n}\n" }, output) + end +end From 478f21c2dad2775ade8bde4bee804795399be49c Mon Sep 17 00:00:00 2001 From: Frederick Cheung Date: Mon, 7 Feb 2022 10:56:38 +0000 Subject: [PATCH 3/3] hook up css sourcemapping processor --- lib/sprockets/railtie.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/sprockets/railtie.rb b/lib/sprockets/railtie.rb index 4d2a40c6..8078c63d 100644 --- a/lib/sprockets/railtie.rb +++ b/lib/sprockets/railtie.rb @@ -8,6 +8,7 @@ require 'sprockets/rails/asset_url_processor' require 'sprockets/rails/base_sourcemapping_url_processor' require 'sprockets/rails/sourcemapping_url_processor' +require 'sprockets/rails/css_sourcemapping_url_processor' require 'sprockets/rails/context' require 'sprockets/rails/helper' require 'sprockets/rails/quiet_assets' @@ -129,6 +130,7 @@ def configure(&block) initializer :asset_sourcemap_url_processor do |app| Sprockets.register_postprocessor "application/javascript", ::Sprockets::Rails::SourcemappingUrlProcessor + Sprockets.register_postprocessor "text/css", ::Sprockets::Rails::CssSourcemappingUrlProcessor end config.assets.version = ""