Enabling pure Nix builds including elm-review & elm-codegen

Since elm-review now has an --offline mode, I wanted to run it in a cacheable, sandboxed Nix build.

I ran into some trouble with missing files, so I tweaked the excellent jeslie0/mkElmDerivation so that it also grabs the docs.json files from package.elm-lang.org, not just the .tar.gz from GitHub.

Now that those files are available in the ELM_HOME of the sandbox, elm-review and elm-codegen both succeed!

I struggled with this, there wasn’t a lot of examples to build off ― so to help the next dev (and maybe myself in 6 months time), here’s what I ended up with:

{ elm-review-tool, elmPackages, lib, pkgs, stdenv, reviewSrc }:
let
  elmVersion = "0.19.1";

  mainApp = builtins.fromJSON (builtins.readFile ../elm.json);

in stdenv.mkDerivation {
  name = "elm-reviewed";
  src = reviewSrc;

  buildInputs = with elmPackages; [ elm elm-json elm-review-tool ];

  installPhase = ''
    ${pkgs.makeDotElmDirectoryCmd {
      elmJson = ../review/elm.json;
      extraDeps = mainApp.dependencies.direct // mainApp.dependencies.indirect;
    }}
    set -e
    mkdir -p .elm/elm-review/2.12.0
    ln -s ../../${elmVersion} .elm/elm-review/2.12.0/${elmVersion}
    elm-review --offline
    echo "passed" > $out
  '';
}

I had been using elm2nix, but I stumbled a lot on adding the docs.json files to that ― mkElmDerivation ended up easier for me.

10 Likes

Well done. I’d be curious to know how many people use nix to build elm projects.

Interesting stuff! I haven’t tried mkElmDerivation because I haven’t switch over to flakes yet.

Here’s the nix expression I use, with both elm-review and elm-test in the checkPhase:

2 Likes

I do! :slight_smile: I have just a few elm apps at the moment and just one of them recently went “in production” and I’m using nix to deploy it.

I’m also using mkElmDerivation which works great in my case.

The experience using nix/nixos for deploying the app has been great so far: in the project’s flake I can build both front-end and back-end and also have a nixos module configuration to start a reverse proxy (caddy) to serve the assets and route requests to the back-end.

Thanks OP for sharing! I’m not using elm-review yet, but it’s great to know it can work with nix.

2 Likes

Hey all, a naive question: I’m guessing this Nix code is required because Elm packages don’t yet exist on Nix?

If they did exist would we just write a static configuration in configuration.nix?

I’ve only just recently discovered NixOS and in the process of evaluating distros (down to NixOS and Fedora SilverBlue) for a new workstation build — moving from Windows 10.

I also want to run Incus for LXC (containers), OCI (Docker) and KVM/QEMU VM guests:
https://wiki.nixos.org/wiki/Incus

Nix(OS) looks great but SilverBlue is easy.

Well, if you’re packaging an application you wrote, somewhere that nix code will be needed :slight_smile: Whether you want to deploy it on your hosts in private or publish it on nixpkgs (the package repository for nix), a package is required and that nix code shall be written.

Dependencies are another thing: if you wrote a package and wanted to depend on something else, you’ll need a way to get that dependency, and that one might be or might be not in nixpkgs. Indeed, there are elm packages in nixpkgs!

1 Like

I think it’s more accurate to say it’s required because elm (via elm.json), elm-review, etc. don’t expose enough information to make a more ergonomic nix helper function.

For example, in the NodeJS ecosystem, package-lock.json does capture the URL and hash of all the dependencies. So there are helper functions in nixpkgs that yield a very simple nix expression:

buildNpmPackage {
  name = "...";
  src = ./.;

  npmDeps = importNpmLock {
    npmRoot = ./.;
  };
}

But elm.json doesn’t capture enough information (and there is no elm-lock.json), so we need a bit more ceremony.

1 Like

An interesting take on packaging for Nix. I’m posting it here in case it helps those packaging Elm dev tools for Nix:

It might not directly provide an answer to the OP but propose some insights and possible ways for improvement.