Do you want to build an ElixirLS?

January 11, 2023 · 3 min read

There are certain instances where you may want to build ElixirLS to run against the version of Elixir/Erlang that you're using. The recommendation from the package is:

If you're packaging these archives in an IDE plugin, make sure to build using the minimum supported OTP version for the best backward-compatibility If you're like me, you may not care to support older versions of Elixir. How do we configure the plugin to run the latest version?

The output I see in VSCode's Output tab (Shift-Command-U on macOS) for the ElixirLS extension:

[Info  - 4:33:53 PM] Started ElixirLS v0.13.0
[Info  - 4:33:53 PM] ElixirLS built with elixir "1.12.3" on OTP "22"
[Info  - 4:33:53 PM] Running on elixir "1.14.2 (compiled with Erlang/OTP 25)" on OTP "25"
[Info  - 4:33:53 PM] Elixir sources not found (checking in /home/build/elixir). Code navigation to Elixir modules disabled.
[Info  - 4:33:54 PM] Loaded DETS databases in 32ms
[Info  - 4:33:54 PM] Starting build with MIX_ENV: test MIX_TARGET: host
[Info  - 4:33:55 PM] Compile took 854 milliseconds

There are numerous articles on building from source. What if we'd prefer to build the extension instead?

Let's unpack that Docker command to perform each step:

  1. Clone the repository with the latest branch: git clone --recursive --branch v0.13.0 https://github.com/elixir-lsp/vscode-elixir-ls.git /tmp/vscode-elixir-ls.
  2. Change to our temp directory: cd /tmp/vscode-elixir-ls.
  3. Install npm dependencies: npm install.
  4. Change to the elixir-ls directory: cd elixir-ls.
  5. Install Elixir dependencies: mix deps.get.
  6. Change to the parent directory: cd ...
  7. Package the extension: npx vsce package.
  8. Make an extensions directory in $HOME: mkdir -p $HOME/extensions.
  9. Copy the extension: cp /tmp/vscode-elixir-ls/elixir-ls-0.13.0.vsix $HOME/extensions.
  10. Remove the temporary directory: rm -rf /tmp/vscode-elixir-ls.

It is crucial to install Elixir v1.14.x and Erlang 25.1.x using your favorite method prior to packaging the new extension. I'm using asdf global to do this, but you could create a local .tool-versions inside the tmp folder if you wish. The extension should now live at /tmp/vscode-elixir-ls/elixir-ls-0.13.0.vsix.

The remaining steps copy the package to a directory the Docker container knows, and it's okay to stop here. Because the prepublish.bash file that executes at step #7 runs mix deps.get, we can eliminate steps 4, 5, and 6. These commands also compile the extension using MIX_ENV=dev, which we may not want. To change this, we can edit the last line in prepublish.bash to MIX_ENV=prod mix elixir_ls.release -o ../elixir-ls-release to compile for production.

Putting all of the (now reduced) commands together:

git clone --recursive --branch v0.13.0 https://github.com/elixir-lsp/vscode-elixir-ls.git /tmp/vscode-elixir-ls
cd /tmp/vscode-elixir-ls
npm install
npx vsce package
mkdir -p $HOME/extensions
cp /tmp/vscode-elixir-ls/elixir-ls-0.13.0.vsix $HOME/extensions
rm -rf /tmp/vscode-elixir-ls

We can install the extension from the VSIX file using the UI or the command code --install-extension $HOME/extensions/elixir-ls-0.13.0.vsix. To take advantage of the new extension in our projects, we need to rm -rf .elixir_ls and navigate to an Elixir file. ElixirLS won't start compiling until an Elixir file is open in the editor, and it'll usually take a few minutes to rebuild everything.

With the new extension installed we should see the change in VSCode's Output tab:

[Info  - 4:35:42 PM] Started ElixirLS v0.13.0
[Info  - 4:35:43 PM] ElixirLS built with elixir "1.14.2" on OTP "25"
[Info  - 4:35:43 PM] Running on elixir "1.14.2 (compiled with Erlang/OTP 25)" on OTP "25"
[Info  - 4:35:43 PM] Elixir sources not found (checking in /home/build/elixir). Code navigation to Elixir modules disabled.
[Info  - 4:35:48 PM] Loaded DETS databases in 414ms
[Info  - 4:35:48 PM] Starting build with MIX_ENV: test MIX_TARGET: host
[Info  - 4:35:49 PM] Compile took 1811 milliseconds