Last active
February 16, 2023 10:37
-
-
Save olivierlacan/92d4706d97ff35176b8982b3aaa034c3 to your computer and use it in GitHub Desktop.
Missing precompile asset finder for Rails 4.x and Sprockets 3.x
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# These instance variables allow you to define which tags we should check | |
# to find references to JavaScript and CSS files. | |
# | |
# Included first are the Rails defaults `javascript_include_tag` and | |
# `stylesheet_link_tag`. Next are examples of custom methods we use at | |
# Code School with the content_for method in order to include JS/CSS in | |
# specific location such as the <head> tag in this instance. | |
JS_TAGS = %w[ javascript_include_tag included_javascript_for_head ] | |
CSS_TAGS = %w[ stylesheet_link_tag linked_stylesheet_for_head ] | |
# This task will first run `git grep` to find any instance in your git repo | |
# of the JS_TAGS and CSS_TAGS. It will then consult the Sprockets manifest and | |
# check for matching logical paths for the files references by your JavaScript | |
# and CSS tags. If the task can't find a mention of the assets you reference | |
# in your tags within the Sprockets manifest, you will see them listed as | |
# output. You should double-check that these references correspond to files | |
# that are added to config.assets.precompile. | |
# | |
# It's likely that these files are not being properly precompiled which means | |
# they're either going to 404 in production (if you have config.assets.compile | |
# set to false) or cause a slow on-demand compilation (if you have | |
# config.assets.compile set to true) | |
namespace :assets do | |
desc 'Check for non-precompiled assets' | |
task :missing_precompile => :environment do | |
javascripts = fetch_references(:js) | |
stylesheets = fetch_references(:css) | |
missing_js_precompiles = check_for_precompiled(javascripts) | |
missing_css_precompiles = check_for_precompiled(stylesheets) | |
if missing_js_precompiles.present? | |
puts "Missing JavaScript precompiles: " | |
puts missing_js_precompiles | |
else | |
puts "No missing JavaScript precompiles found." | |
end | |
if missing_css_precompiles.present? | |
puts "Missing CSS precompiles: " | |
puts missing_css_precompiles | |
else | |
puts "No missing CSS precompiles found." | |
end | |
end | |
def sprockets_manifest_path | |
Dir.glob("public/assets/.sprockets-manifest-*.json").first | |
end | |
def manifest | |
if sprockets_manifest_path.present? | |
JSON.parse File.read(sprockets_manifest_path) | |
else | |
raise "No Sprockets Manifest Found: you need to run `bundle exec rake assets:precompile` first." | |
end | |
end | |
def logical_paths | |
manifest["files"].map { |script| script.last["logical_path"] } | |
end | |
def check_for_precompiled(paths) | |
paths.values.uniq.reject do |script_path| | |
script_path.start_with?(*exclusion_prefixes) or | |
logical_paths.any? { |path| path.include?(script_path) } | |
end | |
end | |
def exclusion_prefixes | |
# // means protocol-less file which means non-local | |
%w[ // ] | |
end | |
def grep(method) | |
%x{ git grep #{method} -- `git ls-files | grep app/views` } | |
end | |
def fetch_references(type) | |
method_names = (type == :js ? JS_TAGS : CSS_TAGS) | |
method_names.inject({}) do |results, method_name| | |
grep(method_name).split("\n").each do |result| | |
file, script = result.split(":") | |
script = script.scan(/'(.*)'/).flatten.first | |
next if script.nil? | |
results[file] = script | |
end | |
results | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is example output when invoked:
bundle exec rake assets:missing_precompile Missing JavaScript precompiles: internal custom/free_weekend sticky-kit/jquery.sticky-kit.js Missing JavaScript precompiles: vendor/dragula vendor/chartist custom/free_weekend vendor/twitter vendor/prism