Install nodejs package to env

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.

  1. Which module(s) are you interested in installing?
  2. Are you aiming to use these module(s) for their executables, for require( '<NAME>' );, or both?
  3. 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?
  4. Are you consuming these modules in a project ( flox.nix ), or a “global” environment?
  5. 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.

  1. Which module(s) are you interested in installing?

@moonrepo/cli
prettier-package-json

  1. 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.

  1. 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.

  1. Are you consuming these modules in a project ( flox.nix ), or a “global” environment?

Not sure what global means here. In the devshell path.

  1. Are you comfortable writing Nix expressions?

Yes, but competent is a quite different question.

1 Like

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.