Skip to content

Instantly share code, notes, and snippets.

@olivierlacan
Last active February 16, 2023 10:37
Show Gist options
  • Save olivierlacan/92d4706d97ff35176b8982b3aaa034c3 to your computer and use it in GitHub Desktop.
Save olivierlacan/92d4706d97ff35176b8982b3aaa034c3 to your computer and use it in GitHub Desktop.
Missing precompile asset finder for Rails 4.x and Sprockets 3.x
# 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
@olivierlacan
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment