Hello,
When I was optimizing our Nix-based CI, a pain point was having to transform dependencies from the Nix store representation into what Mix wanted.
This involved faking the _build/<env>/lib/<app> directory structure and Mix metadata, which was a lot of trial and error to prevent Mix from accidentally recompiling something that was just compiled.
I built
mix_precompiled_deps to help work around that by configuring Mix to consume them from the Nix store directly.
We've been using it for a few months and it's been working really well.
This has enabled some neat things:
- `mix test` and similar inside Nix flake checks, without any additional compilation
- very optimized CI checks, where only dependencies that changed are recompiled
- local development with compiled dependencies coming from a shared binary cache
- on top of that, dialyzer PLTs coming from the shared binary cache too
It does require a few Elixir
patches, though:
1. trust :build in Mix.Dep.load_paths/1
2. trust :build in Mix.AppLoader.load_apps/5
3. add a :precompiled opt to dependencies
All patches were written against Elixir v1.20 and apply cleanly against main.
The first two patches are to trust the paths that a Mix.SCM implementation provides, rather than enforcing the current directory layout.
This doesn't change behavior for the current SCMs and the rest of Mix already reads :build directly.
The third patch gives an option to skip compilation, when they're already precompiled.
Right now Mix recompiles all local dependencies, so this allows an SCM to mark a dependency as immutable and opt out of that.
I went with a per-dependency option here, but something like a new Mix.SCM callback could work too.
If there's interest, I can add tests to these patches and make pull requests.
Thanks!
Disclaimer: the patches were written with AI assistance and reviewed by me.