Last active
October 31, 2024 18:11
-
-
Save bensheldon/ba6532c4216c11dd9ba03487c5a06ee4 to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env ruby | |
# Place in your project (don't forget to chmod +x): | |
# bin/autoload-check | |
# Allow these files to be fixed later | |
allowlist = [ | |
"ExampleClass" # why? | |
] | |
# Load application instead of environment, so that we can configure the autoloader | |
require "./config/application" | |
# Hook into the Rails autoloader to track loading | |
autoloaded_constants = [] | |
Rails.autoloaders.each do |loader| | |
loader.on_load do |cpath, _value, _abspath| | |
autoloaded_constants << [cpath, caller] | |
end | |
end | |
# Hook into Active Support load_hooks too | |
ignorable_load_hooks = [:before_initialize, :after_routes_loaded] | |
ActiveSupport.singleton_class.send(:alias_method, :original_run_load_hooks, :run_load_hooks) | |
ActiveSupport.singleton_class.define_method(:run_load_hooks) do |name, base = Object| | |
autoloaded_constants << ["#{base} (#{name})", caller] unless name.in?(ignorable_load_hooks) | |
original_run_load_hooks(name, base) | |
end | |
# Boot the application | |
Rails.application.initialize! | |
# Remove the allowlisted constants | |
autoloaded_constants.reject! do |(name, _)| | |
allowlist.include?(name) | |
end | |
# Try to find a clean caller | |
autoloaded_constants.each do |autoloaded_const| | |
caller = autoloaded_const[1] | |
autoloaded_const << Rails.backtrace_cleaner.clean(caller).first | |
end | |
if autoloaded_constants.any? | |
puts <<~MESSAGE | |
❌ Autoloaded constants were referenced during during boot. | |
These files/constants were autoloaded during the boot process, | |
which will result in inconsistent behavior and will slow down and | |
may break development mode. Remove references to these constants | |
from code loaded at boot. | |
MESSAGE | |
# Print constants that do have a clean application caller | |
autoloaded_constants.select { |c| c[2].present? }.tap do |constants| | |
const_width = constants.map(&:first).map(&:length).max | |
constants.each do |name, _caller, location| | |
puts "🚨 #{name.ljust(const_width)} referenced by #{location}" | |
end | |
end | |
# Print constants that are referenced inside framework/libraries | |
autoloaded_constants.select { |c| c[2].blank? }.tap do |constants| | |
const_width = constants.map(&:first).map(&:length).max | |
constants.each do |name, caller, _location| | |
puts "🚨 #{name}" | |
puts caller.map { |line| "".ljust(const_width) + line } | |
end | |
end | |
exit 1 # Failure | |
else | |
puts "✅ No autoloading problems discovered! 🎉" | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment