我正在并行开发一个Rails 6应用程序和一个Gem。
在过去,我使用require_reloader Gem,这样当Gem的本地目录中的任何文件发生变化时,Rails都会重新加载Gem。
随着Zeitwerk成为Rails6中的新加载程序,这个Gem似乎不再工作了。
因此,我的问题是:并行开发Gem和Rails6应用程序的规范方法是什么,这样对Gem文件所做的更改就可以在Rails中自动可见?
我也没有找到这个问题的规范解决方案,但在Rails:dummy应用程序中使用的自动重新加载gem文件的上下文中,我找到了一个解决方法:
假设gem文件夹是
~/rails/foo_gem
rails-6-app文件夹为:
~/rails/bar_app
要在文件系统更改时在应用程序中重新加载gem代码,我需要执行三个步骤:
- 注销
foo_gem.rb
中定义的zeitwerk加载程序,该加载程序负责加载不同的gem文件 - 在配置了
enable_reloading
的应用程序的development.rb
中定义一个新的zeitwerk加载程序 - 设置一个文件系统观察程序,并在gem文件更改时触发重新加载
Zeitwerk::Loader
在foo_gem.rb
中
# ~/rails/foo_gem/lib/foo_gem.rb
# require 'foo_gem/bar` # Did not work. Instead:
# (a) use zeitwerk:
require "zeitwerk"
loader = Zeitwerk::Loader.new
loader.push_dir File.join(__dir__)
loader.tag = "foo_gem"
loader.setup
# or (b) use autoload:
module FooGem
autoload :Bar, "foo_gem/bar"
end
注:
- 在过去,我刚刚从一种类似于gem的索引文件中加载了带有
require
的gem的所有ruby文件,这里是foo_gem.rb
。这在这里不起作用,因为zeitwerk似乎忽略了以前用require
加载的文件。相反,我需要为gem创建一个单独的zeitwerk加载程序 - 这个加载程序没有
enable_reloading
,因为否则,无论何时使用gem,都会为这个gem启用重新加载,而不仅仅是在开发gem时 - 我给了这个加载程序一个
tag
,它允许稍后在Zeitwerk::Registry
中找到这个加载程序,以便取消注册 - 不在
foo_gem.rb
中使用zeitwerk,也可以像设计gem那样在那里使用autoload
。如果您想支持早于6的rails版本,这是最好的方法,因为zeitwerk需要rails6+。在这里使用autoload
也使得下一节中的步骤1变得不必要
应用程序的development.rb
中的Zeitwerk::Loader
# ~/rails/bar_app/config/environments/development.rb
# 1. Unregister the zeitwerk loader defined in foo_gem.rb that handles loading
# the different gem files.
#
Zeitwerk::Registry.loaders.detect { |l| l.tag == "foo_gem" }.unregister
# 2. Define a new zeitwerk loader in the development.rb of the app
# that is configured with enable_reloading.
#
gem_root_path = Pathname.new(Gem.loaded_specs["foo_gem"].full_gem_path)
gem_loader = Zeitwerk::Loader.new
gem_loader.push_dir gem_root_path.join("lib")
gem_loader.enable_reloading
gem_loader.setup
# 3. Setup a file-system watcher and trigger a reload when a gem file changes.
#
Listen.to gem_root_path.join("lib"), only: /.rb$/ do
gem_loader.reload
end.start
注:
- Zeitwerk不允许两个加载器管理相同的文件。因此,我需要注销先前定义的标记为
"foo_gem"
的加载程序 - 应用程序中使用的新加载程序具有
enable_reloading
。因此,当将应用程序与rails server
、rails console
一起使用时,或者当运行规范时,可以重新加载gem文件 - zeitwerk不会自动重新加载gem文件。需要一个文件系统观察程序来触发文件系统更改时的重新加载。我没能使
ActiveSupport::FileUpdateChecker
工作。相反,我使用了listenerm作为文件系统观察程序
使用此设置,当使用rails server
、rails console
或bar_app的规范时,foo_gem
的gem文件在编辑后会重新加载,这意味着不再需要重新启动rails server
来获取更改。
但是,我觉得这种变通方法不是很方便。