Skip to content

Commit

Permalink
Introduce zeitwerk:check:boot task
Browse files Browse the repository at this point in the history
This task boots your application and reports if any autoloaded constants were loaded during the boot process.
  • Loading branch information
andrewn617 committed Sep 22, 2024
1 parent c0807dc commit 03d778b
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 0 deletions.
7 changes: 7 additions & 0 deletions railties/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
* Introduce `zeitwerk:check:boot` task

This task boots your application and reports if any autoloaded constants were loaded during the boot
process.

*Andrew Novoselac*

* Do not include redis by default in generated Dev Containers.

Now that applications use the Solid Queue and Solid Cache gems by default, we do not need to include redis
Expand Down
32 changes: 32 additions & 0 deletions railties/lib/rails/tasks/zeitwerk.rake
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ report_unchecked = ->(unchecked) do
puts
end

report_autoloads_on_boot = ->(autoloads) do
puts
puts <<~EOS
WARNING: The following autoload constants were loaded during
the boot process:
EOS
puts

autoloads.each { |constant| puts " #{constant}" }
puts

puts <<~EOS
SUMMARY: #{autoloads.count} autoload constants eagerly loaded during boot.
EOS
end

namespace :zeitwerk do
desc "Check project structure for Zeitwerk compatibility"
task check: :environment do
Expand All @@ -38,4 +54,20 @@ namespace :zeitwerk do
puts "Otherwise, all is good!"
end
end

namespace :check do
task boot: :environment do
begin
autoloads_on_boot = Rails::ZeitwerkChecker.check_boot
rescue Zeitwerk::NameError => e
abort e.message.sub(/#{Regexp.escape(Rails.root.to_s)}./, "")
end

if autoloads_on_boot.empty?
puts "All is good!"
else
report_autoloads_on_boot[autoloads_on_boot]
end
end
end
end
4 changes: 4 additions & 0 deletions railties/lib/rails/zeitwerk_checker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ def self.check
unchecked.select! { |dir| Dir.exist?(dir) && !Dir.empty?(dir) }
unchecked
end

def self.check_boot
Zeitwerk::Registry.loaders.flat_map { |loader| loader.__to_unload.keys }
end
end
19 changes: 19 additions & 0 deletions railties/test/application/zeitwerk_checker_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,23 @@ def boot(env = "development")

assert_equal ["#{app_path}/dir1", "#{app_path}/dir2"], Rails::ZeitwerkChecker.check.sort
end

test "booting the app does not load any autoload constants by default" do
boot

assert_empty Rails::ZeitwerkChecker.check_boot
end

test "loading an autoloaded constant during the boot process is reported" do
app_file "app/models/user.rb", "class User < ActiveRecord::Base; end"
app_file "config/initializers/extra_config.rb", <<~INITIALIZER
Rails.application.config.to_prepare do
Rails.application.config.my_favourite_model = User
end
INITIALIZER

boot

assert_equal ["User"], Rails::ZeitwerkChecker.check_boot
end
end

0 comments on commit 03d778b

Please sign in to comment.