loading...

Setting up `.iex.exs` to Speed up Your Elixir Debugging (and How to Include It in a Docker Image)

noelworden profile image Noel Worden ・4 min read

Did you know that the IEx session looks for a dotfile every time it starts up? And, like most dotfiles, this dotfile can be edited to suite your needs? I had no idea until this week, and I took a little time to setup my project's repo to start using it.

The dotfile

The dotfile is .iex.exs, and when an IEx session starts up, it looks for this file first in the repo, then at the global level, ~/.iex.exs. When starting an Elixir/Phoenix project, this file should be created automatically, but if not, it can be manually added (more on that shortly). The function of this particular dotfile is to allow a user to set commonly used aliases, imports, and variables. This is why I was so motivated to take the time and set one up on our repo; needing to re-establish the imports and aliases every time I entered an IEX session made for less than efficient debugging.

Setting up the dotfile is pretty straightforward. If you have an Elixir/Phoenix project setup, it should be in the repo folder, if not, you can simply create a new file and name it .iex.exs. Once that file exists, open it in your favorite editor, and start creating aliases, imports and/or variables just as you would in a module, for example:

With the above setup, those are are now all available when entering an IEx session:

The session will also warn if the .iex.exs file has compilation errors while it's evaluating it on startup. for instance, if I were to forget to add the closing bracket to example_variable:

This is the error shown on the session startup:

If the file doesn't compile, none of its content will be available in the IEx session. Also, when changes are made to the .iex.exs file, a complete restart of the IEx session is necessary to see those changes.

Incorporating with Docker

All that setup is great, but what if the project is Dockerized and the file is not already present in the image, and therefore not in the container? This is what initially threw me for a loop. Most of the documentation I came across (which isn't a ton) simply stated that this dotfile is 'generated upon creation of a new project'. I spent more time than I'd like to admit digging around my local repo folder and the file structure of the built container, to ultimately find nothing.

Then I started to look at the structure that builds the docker images, and this line from our Dockerfile stuck out to me:

I am a far stretch from a Docker expert, but I've been in this file before, and have a basic understanding of whats happening. Once things started clicking, I theorized that if these mix.exs and mix.lock files are being copied from my local repo and ultimately executed, why couldn't I just create a local version of .iex.exs and include that in the COPY command?

So, I created the dotfile, threw in a quick alias MyApp.Repo, edited the Dockerfile to the above example, and re-built the image. There were no build errors, no errors when I entered the IEx session, and to my surprise and delight the alias was ready for me to use:

Updating on the Fly

There was one small thing that was bugging me about this flow. It's great that now there is a file where commonly used aliases, imports and variables can be used, but what if I wanted to update that file in real-time to add an variable I knew I'd be using for the next few days? Would I really have to completely re-build the image so that the changes were recognized by the IEx session?

Because I had been digging around the guts of the container earlier in my adventure, my first solution was in that vein. I figured I could just drop into a bash session in the running container, find the .iex.exs file, and alter it right there. I tried it, it worked, it was faster than altering the local version and re-building the image, but it felt a bit hacky.

After presenting this to a colleague, he also agreed it was less than ideal, and had a much better solution: include .iex.exs in the services > web > volumes section of the docker-compose.yml file.

Once I saw the other files included in the volumes section it made sense at a high level what was happening, but I still had my colleague spell it out in detail so I fully understood the purpose of adding the dotfile here. The files in this volumes section will override the corresponding files in the container. The files in the container exist, unchanged, but the corresponding local file will be given priority. This means that changes made to that file locally will be read by, and therefore available in the container. This is the line I added to docker-compose.yml:

With that line added, and a restart of the container, my local copy of iex.exs can be edited and I'm able to see those changes the next time I start an IEx session.

The jumping off point for all of this work was a this great post detailing tips about the IEx shell, I strongly recommend everyone giving it a read. From this article I also tweaked the alias I use to enter an IEx session so that I now have a saved history from session to session. That saved history, along with all of the projects aliases and imports being loaded on session startup are going to make my debugging life much more efficient.


This post is part of an ongoing This Week I Learned series. I welcome any critique, feedback, or suggestions in the comments.

Discussion

pic
Editor guide