My dev env uses several tools installed from npmjs.com . How do I install a nodejs module ‘globally’ with flox? - they do not show up in search.
Howdy, this is one that I actually have a lot of experience with, so I’m sure I can help you out.
I’d like to gather a bit of context first so I can recommend the appropriate approach.
- Which module(s) are you interested in installing?
- Are you aiming to use these module(s) for their executables, for
require( '<NAME>' );
, or both? - Do you automatic updates from a
package.json
,package-lock.json
,yarn.lock
, etc, or are your updates infrequent enough that you could manually trigger a “regeneration” script? - Are you consuming these modules in a project (
flox.nix
), or a “global” environment? - Are you comfortable writing Nix expressions?
The “simplest” approach that doesn’t require any nix
experience is simply to install npm
or yarn
using flox
, and running something like:
envName="${FLOX_ACTIVE_ENVIRONMENTS##:*}";
export NPM_CONFIG_PREFIX="/tmp/${envName}-npm";
mkdir -p "$NPM_CONFIG_PREFIX";
export NODE_PATH="$NPM_CONFIG_PREFIX/lib/node_modules${NODE_PATH:+:$NODE_PATH}";
export PATH="$PATH:$NPM_CONFIG_PREFIX/bin";
npm install -g lodash@4.17.21;
npm install -g pacote@13.3.0;
# ...
While this process certainly isn’t ideal, it would provide an isolated env associated with your workspace that is reproducible.
For an “improved” experience you could create nix
recipes and ( optionally ) use flox publish
to maintain a catalog of globally installable modules. There’s a variety of useful tools which largely automate this process ( one that I authored is here: GitHub - aakropotkin/floco: Using Nix to put NPM and Yarn in a coffin ). Knowing more about the “context” questions above would help me make recommendations.
- Which module(s) are you interested in installing?
@moonrepo/cli
prettier-package-json
- Are you aiming to use these module(s) for their executables, for
require( '<NAME>' );
, or both?
The clis. Any libs would not need to be in PATH or installed without pnpm and am not looking at replacing pnpm with nix at the moment. Moon is the only one I really need to be in PATH rather than installed in the local node_modules. I could invoke it with run scripts or cargo-make or something but figured I should solve this question before getting too deep into flox or nix.
- Do you automatic updates from a
package.json
,package-lock.json
,yarn.lock
, etc, or are your updates infrequent enough that you could manually trigger a “regeneration” script?
Moonrepo changes quite a bit. I havnt used renovate’s new nix support yet but plan too.is a quite different question.
- Are you consuming these modules in a project (
flox.nix
), or a “global” environment?
Not sure what global means here. In the devshell path.
- Are you comfortable writing Nix expressions?
Yes, but competent is a quite different question.
Alright so the fact that these are needed as CLI tools in PATH
rather than members of a node_modules/
directory makes things significantly easier.
Essentially the process will be to package those two tools up using a node
to nix
translation tool to create a custom package that flox
can use.
I’ll use moon
as an example to package, which you can follow along with. I chose the translator floco
, but node2nix
or other translators would work fine as well.
Here’s the process from scratch in an empty project area, you could perform roughly the same steps in an existing flox
project ( probably edit flake.nix
manually for an existing project ).
$ mkdir -p moon;
$ cd moon;
$ git init;
# Based on the usual `flox init -t project' template:
# Add `floco' to our inputs, and set a new description
$ cat <<'EOF' > flake.nix
{
description = "moon command line and core system";
inputs.flox-floxpkgs.url = "github:flox/floxpkgs";
inputs.floco.url = "github:aakropotkin/floco";
outputs = args @ {flox-floxpkgs, ...}: flox-floxpkgs.project args (_: {});
}
EOF
$ mkdir -p pkgs/moon;
$ pushd pkgs/moon;
# Generate a `nix' build for the package.
$ flox nix run 'github:aakropotkin/floco#fromRegistry' -- @moonrepo/cli@1.1.1;
# Adapt some boilerplate taken from `floco' "registry" project template to play
# nicely with `flox':
$ cat <<'EOF' > ./default.nix
{
lib
, inputs
, system
}: let
ident = "@moonrepo/cli";
version = "1.1.1";
fmod = lib.evalModules {
modules = [
inputs.floco.nixosModules.floco
{ config.floco.settings = { inherit system; }; }
./pdefs.nix
{
config.floco.packages.${ident}.${version} = {
# Force copying of tree during `install' so we can copy binaries.
installed.override.copyTree = true;
# This package has no runtime deps, the declared dependencies are only
# required during installation, so we can drop them.
trees.global = null;
};
}
];
};
in fmod.config.floco.packages.${ident}.${version}.global // {
meta.description = "moon command line and core system";
meta.mainProgram = "moon";
meta.license = lib.getLicenseFromSpdxId "MIT";
}
EOF
$ popd;
$ git add ./flake.nix ./pkgs;
$ flox build moon;
$ ls ./result/bin;
$ ls ./result/lib/node_modules/@moonrepo/cli/;
Because moon
has an “install script” we added a few extra lines to a default.nix
file, but for prettier
and any other package that doesn’t have a postinstall
script you could drop lines 14-22.
This is essentially similar to packaging any node
project using nix
, the main difference is that flox
expects a standardized file hierarchy, so you’ll want to place any default.nix
files under ./pkgs/<NAME>/default.nix
.
Ideally we’ll get a more streamlined process for creating node
packages, but for now this should get you up and running. Let me know if there’s anything else I can help with.