Add source map for sprockets
This commit is contained in:
@ -1,3 +1,5 @@
|
||||
//= link_tree ../images
|
||||
//= link_directory ../javascripts .js
|
||||
//= link_directory ../javascripts .js.map
|
||||
//= link_directory ../stylesheets .css
|
||||
//= link_directory ../stylesheets .css.map
|
||||
|
87
lib/tasks/sourcemap.rake
Normal file
87
lib/tasks/sourcemap.rake
Normal file
@ -0,0 +1,87 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Adapted from https://github.com/rails/sprockets/issues/502#issuecomment-1030634236
|
||||
|
||||
SOURCE_EXTENSIONS = %w[.css .js].freeze
|
||||
|
||||
namespace :assets do
|
||||
def append_sourcemap
|
||||
manifest_path = Dir[Rails.public_path.join('assets/.sprockets-manifest-*.json').to_s].max {|a, b| File.ctime(a) <=> File.ctime(b) }
|
||||
return unless manifest_path
|
||||
|
||||
manifest_json = JSON.parse(File.read(manifest_path))
|
||||
assets = manifest_json['assets']
|
||||
manifest = manifest_json['files']
|
||||
|
||||
assets.each do |name, digested|
|
||||
ext = File.extname(name)
|
||||
next unless SOURCE_EXTENSIONS.include? ext
|
||||
|
||||
# Get the source map file from the manifest
|
||||
map_digested = assets["#{name}.map"]
|
||||
next unless map_digested
|
||||
|
||||
# Parse the source map file
|
||||
source_map = JSON.parse(File.read(Rails.public_path.join('assets', map_digested).to_s))
|
||||
|
||||
# Replace the source map file name with the digested one
|
||||
if source_map['sections'].present?
|
||||
source_map['sections'].map! do |section|
|
||||
section['map']['sources'].map! {|source| assets[source] || source }
|
||||
section
|
||||
end
|
||||
elsif source_map['sources'].present?
|
||||
source_map['sources'].map! {|source| assets[source] || source }
|
||||
end
|
||||
|
||||
# Write the source map file
|
||||
asset_source = Rails.public_path.join('assets', map_digested).to_s
|
||||
write_asset(asset_source, source_map.to_json, manifest)
|
||||
|
||||
# Construct the source map link
|
||||
file = Rails.root.join("public/assets/#{digested}")
|
||||
mapping_string = "sourceMappingURL=#{map_digested}"
|
||||
|
||||
mapping_string = case ext
|
||||
when '.css' then "/*# #{mapping_string} */"
|
||||
when '.js' then "//# #{mapping_string}"
|
||||
end
|
||||
|
||||
# Read the source map file and append the source map link
|
||||
write_asset(file, "#{file.read}\n#{mapping_string}", manifest)
|
||||
end
|
||||
|
||||
File.write(manifest_path, manifest_json.to_json)
|
||||
end
|
||||
|
||||
def write_asset(filename, content, manifest)
|
||||
File.write(filename, content)
|
||||
mtime = Sprockets::PathUtils.stat(filename)&.mtime
|
||||
compress_asset(filename, content, mtime)
|
||||
manifest[File.basename(filename)].merge!(changed_manifest(content, mtime))
|
||||
end
|
||||
|
||||
def compress_asset(source_filename, content, mtime)
|
||||
target = "#{source_filename}.gz"
|
||||
|
||||
File.open(target, 'wb') do |file|
|
||||
Sprockets::Utils::Gzip::ZlibArchiver.call(file, content, mtime)
|
||||
end
|
||||
end
|
||||
|
||||
def changed_manifest(content, mtime)
|
||||
digest = Sprockets::DigestUtils.digest(content)
|
||||
hexdigest = Sprockets::DigestUtils.pack_hexdigest(digest)
|
||||
|
||||
{
|
||||
'mtime' => mtime,
|
||||
'size' => content.bytesize,
|
||||
'digest' => hexdigest,
|
||||
'integrity' => Sprockets::DigestUtils.hexdigest_integrity_uri(hexdigest),
|
||||
}
|
||||
end
|
||||
|
||||
task precompile: :environment do
|
||||
append_sourcemap
|
||||
end
|
||||
end
|
Reference in New Issue
Block a user