Learn Phoenix LiveView is the comprehensive tutorial that teaches you everything you need to build a complex, realistic, fully-featured web app with Phoenix LiveView. Click here to learn more!
Christmas has come early - Elixir 1.18 has been released! Combined with the recent announcement that Phoenix LiveView has reached its long-awaited v1.0.0, it’s a good time to be an Elixir developer.
Elixir 1.18 contains some major enhancements, which you can read about in the changelog, but here I’ll focus on one minor new feature: IEx’s new :auto_reload
config option.
In short: IEx (Elixir’s REPL console) can now automatically reload your code changes without you needing to call recompile()
. It’s a nice improvement, but there are some subtleties to be aware of, so let’s go over them in detail.
Let’s use mix new
to generate a new Mix project called “example”:
$ mix new example
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/example.ex
* creating test
* creating test/test_helper.exs
* creating test/example_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd example
mix test
Run "mix help" for more commands.
$ cd example
The generated project contains a module with one function, Example.hello/0
. Fire up a console with iex -S mix
and call it:
iex> Example.hello()
:world
Now edit the function so it returns Portuguese instead of English:
# lib/example.ex
defmodule Example do
…
def hello do
- :world
+ :mundo
end
end
This change doesn’t take effect in IEx automatically:
iex> Example.hello()
:world
To use the new code, we must manually recompile using recompile/0
:
iex> recompile()
Compiling 1 file (.ex)
Generated example app
:ok
iex> Example.hello()
:mundo
Prior to Elixir 1.18, recompile/0
was the only way to make our updated code available in IEx without closing the console and opening a new one. But now there’s a new way.
Elixir 1.18 introduces a new configuration option for IEx, :auto_reload
. By default it’s false
, as you can see by calling IEx.configuration/0
:
iex> IEx.configuration()
[
…
auto_reload: false
]
To set it to true
, use IEx.configure/1
:
iex> IEx.configure(auto_reload: true)
:ok
iex> IEx.configuration()[:auto_reload]
true
Better yet, put the configuration code in a file called .iex.exs
in the project root:
# .iex.exs
+IEx.configure(auto_reload: true)
Now the code will be run automatically when you open an IEx console, so you don’t have to call it manually every time.
Let’s update our “hello, world” function again, this time changing the output from Portuguese to French:
# lib/example.ex
defmodule Example do
…
def hello do
- :mundo
+ :monde
end
end
With the new configuration, you might expect IEx to automatically use the new function. But it hasn’t happened yet. 🤔
iex> Example.hello()
:mundo
Here’s the thing: IEx now automatically reloads, but it doesn’t automatically recompile. We still need to recompile the Example
module somehow, for example by calling mix compile
in a separate terminal window to the one running IEx:
$ mix compile
Compiling 1 file (.ex)
Generated example app
Now, with :auto_reload
set to true
, IEx detects that the compiled Example
module[1] has changed, and quietly loads the new version:
iex> Example.hello()
:monde
By itself this doesn’t make much difference - typing mix compile
is hardly more convenient than typing recompile()
. It becomes useful when another process is watching for changes and automatically recompiling.
Your IDE might do this. If not, one option is to use entr
.
We’ll be using git ls-files
to make this work, so first we need to initialize a git repo:
$ git init
$ git add .
$ git commit -m "initial commit"
You can install entr
on a Mac using brew install entr
. Then to automatically recompile files when they change, run:
$ git ls-files | entr mix compile
Let’s change the function one last time, to German:
# lib/example.ex
defmodule Example do
…
def hello do
- :monde
+ :Welt
end
end
Back in the terminal that’s running entr
, you’ll see the recompilation happened automatically:
Compiling 1 file (.ex)
Generated example app
And IEx picked up the changes:
iex> Example.hello()
:Welt
The new :auto_reload
option is part of a set of changes to support Elixir’s new Official Language Server project. The changelog explains it well, so I won’t repeat it: read about it here.
It’s still early days but I’m looking forward to using this new feature and everything else in Elixir 1.18.
Merry Christmas 🎄
Edit: José Valim points out another improvement in 1.18 that I wasn’t aware of:
[P]reviously, if you did this:
- Started
iex -S mix
- Changed a file
- Called
mix compile
- Called
recompile()
in IEx
recompile()
would not pick up the new module at all, because it had already been compiled. Elixir v1.18 makes it sorecompile()
works consistently AND adds theauto_reload
option. Overall, it is all about playing better with multiple OS processes.
No spam. Unsubscribe any time.
Thanks to members of Elixir Forum, including José Valim himself, and also to Benjamin Milde (@lostkobrakai) and Thomas Depierre (@di4na) on the Elixir Slack, who replied to my questions about :auto_reload
and helped clarify up my understanding of this new feature.
Image credit: Jay Heike on Unsplash.