67

I'm currently learning Elixir by going through the OTP and mix tutorial on the elixir-lang website, and I'm having trouble finding out how to recompile and reload the project from within the shell.

In Erlang I would do make:all([load]) and it would compile and load any changes that occurred. However, in iex that always says :up_to_date, which does make sense, as Elixir uses mix for it's compiling needs.

I can't find any equivalent from within iex.

Freedom_Ben
  • 11,247
  • 10
  • 69
  • 89
KallDrexx
  • 27,229
  • 33
  • 143
  • 254
  • 1
    Did you try `r/1` in `iex`? Note that you can invoke a help in `iex` by calling `h()`. See around if some of that can help you. – Guedes Apr 08 '16 at 02:23
  • I hadn't known about `r/1` but that still isn't equivalent. I have to manually enter each module I have updated code for where as `make:all([load])` would auto-detect updated modules and recompile/reload them. – KallDrexx Apr 08 '16 at 02:42
  • Maybe you are looking for something related to http://stackoverflow.com/questions/32540703/make-elixir-app-recompile-and-reload-on-source-code-change and https://groups.google.com/forum/#!topic/elixir-lang-talk/uU8K2NJAE70? It seems that this is duplicated with those one. – Guedes Apr 08 '16 at 03:33
  • I was wondering the same and I decided to develop [lettuce](https://github.com/gilacost/lettuce). It is a gen server that watches your files and recompiles the project for you without leaving the IEx. Check it out ! – Josep Lluis Apr 01 '20 at 07:04

3 Answers3

119

You can use the IEx.Helpers.recompile/0 function.

Recompiles the current Mix application.

This helper only works when IEx is started with a Mix project, for example, iex -S mix. Before compiling the code, it will stop the current application, and start it again afterwards. Stopping applications are required so processes in the supervision tree won't crash when code is upgraded multiple times without going through the proper hot-code swapping mechanism.

Changes to mix.exs or configuration files won't be picked up by this helper, only changes to sources. Restarting the shell and Mix is required in such cases.

If you want to reload a single module, consider using r ModuleName instead.

NOTE: This feature is experimental and may be removed in upcoming releases.

From https://github.com/elixir-lang/elixir/blob/v1.2.4/lib/iex/lib/iex/helpers.ex#L56-L93

Sam Houston
  • 3,413
  • 2
  • 30
  • 46
Dogbert
  • 212,659
  • 41
  • 396
  • 397
  • 2
    Would `c("filename.ex")` work the same way @Dogbert? Just curious. – Onorio Catenacci Apr 08 '16 at 12:55
  • @OnorioCatenacci no, it just recompiles a file, period. – Andrei Dziahel Apr 08 '16 at 18:20
  • IEx.Helpers.recompile/0 will crash running processes. It will also ignore compile errors by not loading the failed modules. This makes it unusable for live coding. – Vans S Feb 26 '17 at 17:57
  • 1
    The behaviour of this function has changed - it no longer restarts the application. Also, the documentation has moved and is now [here](https://hexdocs.pm/iex/IEx.Helpers.html#recompile/0). – legoscia Jul 31 '18 at 14:18
23

February 26, 2017:

To hot load components in a running elixir system with the lowest chance of something going wrong use:

case c(filename_ex, :in_memory) do
    [] -> :ignore
    [mod|_] -> r(mod)
end

Original answer:

In elixir 1.3.0 recompile does not restart the application anymore. So the correct way to check if any source changed and hotload is:

iex> recompile()

NOTE: I want to add that due to issues with removing modules during the recompile you will most likely crash processes while the recompile is occurring if you have in flight messages like a gen_statem with a state_timeout.

NOTE2: Using recompile/0 if you make an error in a source file, the project will compile with that source file missing and unloaded.

Vans S
  • 1,743
  • 3
  • 21
  • 36
8

The one downside to @Dogbert's answer I found is it does a complete stop and restart of the application. While this is ok in theory it failed in my current project as my project dependend on Ranch, but everything didn't get stopped properly. This meant things broke when it tried to restart the project it failed because the socket was already in use.

Long story short, I looked at the helper's code and added the following function to my module:

  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  

Now I can enter MyApp.recompile and everything is hot-reloaded without the application restarting.

KallDrexx
  • 27,229
  • 33
  • 143
  • 254