Skip to content

Instantly share code, notes, and snippets.

@ersinakinci
Last active March 3, 2020 20:46
Show Gist options
  • Save ersinakinci/6477ceb402875703ad0fd532dffd4e21 to your computer and use it in GitHub Desktop.
Save ersinakinci/6477ceb402875703ad0fd532dffd4e21 to your computer and use it in GitHub Desktop.
Notes and gotchas while using Nix

nix-env

Installing

  • If you install a package that has periods in the attribute path, you'll need to wrap the subpath on the command line using escaped double quotation marks. For example, packages generated by the node2nix tool can have NPM package versions affixed to the attribute, depending on how node2nix is set up. Version ^0.0.1-1 of redux-devtools-cli may be represented as nodeModules.redux-devtools-cli-^0.0.1-1, which on the command line would be installed like so: npm -f '<nixpkgs>' -iA "nodeModules.\"redux-devtools-cli-^0.0.1-1\"".

node2nix

Ways of installing Node packages

Let's say that you want to make some NPM packages available for your Nix environment (e.g., nix-shell, home-manager). Here are the main patterns that I've identified:

If you're making a shell, add your packags to package.json's dependencies

Any dependencies added to a standard package.json will get pulled into your nix-shell if you use the shell derivation generated by node2nix. To make this seamless, node2nix generates a custom package containing just your NPM dependencies and makes the NPM modules contained within this package available to the shell via a shell hook. The shell hook in turn sets PATH and NODE_PATH to point to the appropriate NPM modules.

Pros:

  • Arguably the cleanest approach, maintains maximum compatibility with a standard package.json.

Cons:

  • Only works if you're using nix-shell and specifically the shell derivation generated by node2nix. For example, you can't expose NPM packages to your system environment by putting them inside the dependencies field of a dummy package.json and then installing the generated package, because the dependencies are only exposed to the environment through node2nix's shell derivation.
  • Since you have to use node2nix's shell derivation, it becomes a bit awkard to get non-NPM dependencies and tooling into the shell environment. You end up having to modify the shell derivation using overrideAttrs and the like, which isn't a clean approach. node2nix doesn't expose the various bits that go into the shell derivation in a modular way for you to build your own custom shells.

If you're trying to get NPM packages in any non-shell environment, create a package.json with an array of your NPM packages

If you create a package.json that consists of an array with your desired NPM packages, node2nix will generate a set of Nix packages, one for each NPM package. You can then merge this set with the top-level nodePackages Nixpkgs attribute in an overlay. For example:

# ~/.config/overlays/nodePackages.nix

self: super:
{
  # ~/nix/nodePackages contains your generated default.nix, node-packages.nix,
  # node-env.nix, and your source package.json.
  nodePackages = super.nodePackages // super.callPackage ../../../nix/nodePackages {};
}

Pros:

  • A fairly clean approach. Requires a non-standard package.json, but you can always name this something different like packages-for-overlay.json and use the -i option. I.e., node2nix -i packages-for-overlay.json.
  • The only game in town if you want to expose NPM packages within your Nix environment without relying on NPM, Yarn, etc.

Cons:

  • Unlike packages listed in the dependencies field of a standard package.json, node2nix builds every package installed this way from scratch using npm rebuild on the sources instead of grabbing a pre-built version from NPM--which, to be fair, is The Nix Way™️ and maintains purity. On the other hand, it means that a lot of packages that you'd assume just work won't install without further configuration to make sure their build-time dependencies are in place (see below).
  • Because this is the only way currently to install NPM packages using node2nix in a non-shell environment, you have no choice but to build every such package from source, if this is your use case. There's no way around it when using standard node2nix without any hackery.

If you're trying to expose build-time tooling to build your NPM packages from scratch, create a supplement.json

Some NPM packages require tooling at build-time (e.g., TypeScript, Gulp). You can include these using a supplement.json file that's an array with your tooling in it. Your tooling packages then get passed into the buildInputs attribute of your target packages' derivations. Simply pass in supplement.json using --suplement-input: node2nix -i package.json --supplement-input supplement.json.

Pros:

  • Keeps build tooling separate from target packages.
  • The tooling packages don't get added to the package set generated by node2nix that has your target packages, keeping it clean.
  • Works whether you're using the standard package.json dependencies approach or the package.json array approach.

Cons:

  • Like any target packages listed in a package.json array, each of the supplement.json packages are built from scratch. That means that you need to include the recursive build-time dependencies for your target packages in supplement.json. That means that you must list the build-time dependencies of your target packages, the build-time dependencies of your build-time dependencies, the build-time dependnecies of the build-time dependencies of your build-time dependencies...
  • You have to keep track of another file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment