Skip to content

Instantly share code, notes, and snippets.

@bensheldon
Last active October 31, 2024 18:11
Show Gist options
  • Save bensheldon/ba6532c4216c11dd9ba03487c5a06ee4 to your computer and use it in GitHub Desktop.
Save bensheldon/ba6532c4216c11dd9ba03487c5a06ee4 to your computer and use it in GitHub Desktop.
#!/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