如何在iex中重新编译Elixir项目并重新加载?

69

我目前正在通过elixer-lang网站上的OTP和mix教程学习Elixir技术,但我在尝试从shell内部重新编译和重新加载项目时遇到了麻烦。

在Erlang中,我会使用make:all([load])重新编译并加载任何更改。 但是,在iex中,它总是显示:up_to_date,这是有道理的,因为Elixir使用mix进行编译。

我找不到在iex中的任何等效命令。


1
你在 iex 中尝试过 r/1 吗?请注意,您可以通过调用 h()iex 中调用帮助。看看周围是否有一些可以帮助您的东西。 - Guedes
我之前不知道 r/1,但那仍然不等同于 make:all([load])。我必须手动输入我已更新代码的每个模块,而 make:all([load]) 可以自动检测更新的模块并重新编译/加载它们。 - KallDrexx
也许你正在寻找与 https://dev59.com/_lwY5IYBdhLWcg3wgX-V 和 https://groups.google.com/forum/#!topic/elixir-lang-talk/uU8K2NJAE70? 相关的内容。看起来这与那些是重复的。 - Guedes
我也曾经有同样的疑问,于是我决定开发lettuce。它是一个gen server,可以在不离开IEx的情况下监视您的文件并为您重新编译项目。快去看看吧! - Josep Lluis
3个回答

120
你可以使用IEx.Helpers.recompile/0函数。
重新编译当前的Mix应用程序。此助手仅在使用Mix项目启动IEx时有效,例如iex -S mix。编译代码之前,它会停止当前应用程序,之后再次启动。为了避免升级代码时多次不经过适当的热代码交换机制而使监管树中的进程崩溃,需要停止应用程序。
只有源代码的更改才会被此帮助程序捕获,mix.exs或配置文件的更改将不会被捕获。对于这种情况,需要重新启动shell和Mix。
如果要重新加载单个模块,请考虑使用r ModuleName
注意:此功能是实验性的,可能会在未来的版本中删除。
来源:https://github.com/elixir-lang/elixir/blob/v1.2.4/lib/iex/lib/iex/helpers.ex#L56-L93

2
c("filename.ex")会和@Dogbert一样工作吗?只是好奇。 - Onorio Catenacci
@OnorioCatenacci 不,它只是重新编译一个文件,没有别的。 - Andrei Dziahel
IEx.Helpers.recompile/0 会导致正在运行的进程崩溃。它还会通过不加载失败的模块来忽略编译错误。这使得它无法用于实时编码。 - Vans S
1
这个函数的行为已经改变了 - 它不再重新启动应用程序。此外,文档已经移动,现在在这里:https://hexdocs.pm/iex/IEx.Helpers.html#recompile/0。 - legoscia

24

2017年2月26日:

要在一个正在运行的Elixir系统中以最低的出错几率热加载组件,请使用以下方法:

case c(filename_ex, :in_memory) do
    [] -> :ignore
    [mod|_] -> r(mod)
end
在 Elixir 1.3.0 中,重新编译不再重新启动应用程序。因此,检查是否有任何源更改并进行热加载的正确方法是:
iex> recompile()

注意:由于重新编译过程中移除模块存在问题,如果您的操作中有未完成的消息(如具有状态超时的gen_statem),则在重新编译时很可能会导致进程崩溃。

注意2:如果您在源文件中出现错误,使用recompile/0,该项目将在缺少和未加载该源文件的情况下编译。


8
@Dogbert的答案唯一的缺点是,它会完全停止应用程序并重新启动。虽然理论上这没问题,但在我的项目中失败了,因为我的项目依赖于Ranch,但不是所有东西都被正确地停止了。这意味着在尝试重新启动项目时,由于套接字已经在使用中,所以会出现故障。简而言之,我查看了助手的代码,并将以下函数添加到我的模块中:
  def recompile() do
    Mix.Task.reenable("app.start")
    Mix.Task.reenable("compile")
    Mix.Task.reenable("compile.all")
    compilers = Mix.compilers
    Enum.each compilers, &Mix.Task.reenable("compile.#{&1}")
    Mix.Task.run("compile.all")
  end  

现在我可以输入MyApp.recompile,而无需重新启动应用程序即可进行热重载。

这在1.5版本中不再起作用。我得到了[:noop, :noop] - Mr H

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