Rails 6:在更改时自动重新加载本地gem

3

我正在开发一个Rails 6应用程序和一个Gem。

过去,我使用require_reloader Gem,这样当Gem本地目录中的任何文件更改时,Rails会重新加载该Gem。

随着Zeitwerk成为Rails 6中的新加载器,这个Gem似乎不再起作用了。

所以我的问题是:有什么权威的方法可以同时开发Gem和Rails 6应用程序,以便对Gem文件所做的更改在Rails中自动可见?

1个回答

1
我也没有找到这个问题的规范解决方法,但是在Rails: Auto-reload gem files used in dummy app的上下文中,我找到了一个解决方法:

假设,这个 gem 文件夹是

~/rails/foo_gem

"rails-6-app" 文件夹的位置是:
~/rails/bar_app

为了在文件系统更改时重新加载应用程序中的 gem 代码,我需要执行三个步骤:
  1. 取消注册在 foo_gem.rb 中定义的负责加载不同 gem 文件的 zeitwerk 加载器。
  2. 在应用程序的 development.rb 中定义一个新的 zeitwerk 加载器,该加载器配置了 enable_reloading
  3. 设置一个文件系统观察器,并在 gem 文件更改时触发重新加载。

foo_gem.rb 中的 Zeitwerk::Loader

# ~/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 文件。这在这里不起作用,因为 zeitwerk 似乎会忽略先前使用 require 加载的文件。相反,我需要为 gem 创建一个单独的 zeitwerk 加载器。
  • 这个加载器没有 enable_reloading,否则,在使用 gem 时,会启用此 gem 的重新加载,而不仅仅是在开发 gem 时。
  • 我给加载器添加了一个标签,这样可以在以后的 Zeitwerk::Registry 中找到这个加载器,以便注销它。
  • 除了在 foo_gem.rb 中使用 zeitwerk 外,也可以像 devise gem 那样使用 autoload。如果您想支持早于 6 版本的 rails,则这是最佳方法,因为 zeitwerk 需要 rails 6+。在这里使用 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 serverrails console 或运行规范时,可以重新加载 gem 文件。
  • gem 文件不会自动由 zeitwerk 重新加载。需要一个文件系统监视器来在文件系统更改时触发重新加载。我无法使 ActiveSupport::FileUpdateChecker 工作。取而代之,我使用了 listen gem 作为文件系统监视器。
使用这个设置,当使用 rails serverrails console 或 bar_app 的规范时,foo_gem 的 gem 文件在被编辑后会被重新加载,这意味着不再需要重新启动 rails server 来获取更改。
然而,我并不觉得这种解决方法很方便。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接