我正在并行开发 Rails 6 应用程序和 Gem。
过去,我使用了require_reloader Gem,这样当 Gem 的本地目录中的任何文件发生更改时,Rails 都会重新加载 Gem。
随着 Zeitwerk 成为 Rails 6 中的新加载程序,这个 Gem 似乎不再工作了。
所以我的问题是:并行开发 Gem 和 Rails 6 应用程序以便对 Gem 文件所做的更改在 Rails 中自动可见的规范方法是什么?
我正在并行开发 Rails 6 应用程序和 Gem。
过去,我使用了require_reloader Gem,这样当 Gem 的本地目录中的任何文件发生更改时,Rails 都会重新加载 Gem。
随着 Zeitwerk 成为 Rails 6 中的新加载程序,这个 Gem 似乎不再工作了。
所以我的问题是:并行开发 Gem 和 Rails 6 应用程序以便对 Gem 文件所做的更改在 Rails 中自动可见的规范方法是什么?
我也没有找到解决这个问题的规范解决方案,但是,在Rails: Auto-reload gem files used in dummy app的上下文中,找到了一种解决方法:
假设 gem 文件夹是
~/rails/foo_gem
rails-6-app 文件夹是:
~/rails/bar_app
要在应用程序中重新加载文件系统更改的 gem 代码,我需要执行三个步骤:
foo_gem.rb
取消注册处理加载不同 gem 文件的 zeitwerk 加载程序。development.rb
配置了enable_reloading
.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
笔记:
require
从一种类似于 gem 的索引文件中加载 gem 的所有 ruby 文件,这里:foo_gem.rb
. 这在这里不起作用,因为 zeitwerk 似乎忽略了以前加载的文件require
。相反,我需要为 gem 创建一个单独的 zeitwerk 加载器。enable_reloading
,因为否则,无论何时使用 gem,都会为这个 gem 启用重新加载,而不仅仅是在开发 gem 时。tag
,它允许稍后找到这个加载器Zeitwerk::Registry
以便取消注册它。foo_gem.rb
,还可以像 devise gem 那样autoload
使用那里。如果您想支持早于 6 的 rails 版本,这是最好的方法,因为 zeitwerk 需要 rails 6+。在此处使用也使下一节中的步骤 1 变得不必要。autoload
Zeitwerk::Loader
在development.rb
应用程序中# ~/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
笔记:
"foo_gem"
。enable_reloading
. 因此,当使用带有rails server
,的应用程序rails console
或运行规范时,可以重新加载 gem 文件。ActiveSupport::FileUpdateChecker
工作。相反,我使用了listen gem 作为文件系统观察器。通过此设置,当使用bar_apprails server
的、 或 specs 时,编辑后的 gem 文件会重新加载,这意味着不再需要重新启动来获取更改。rails console
foo_gem
rails server
但是,我发现这种解决方法不是很方便。