Home Explore Blog CI



nixpkgs

7th chunk of `doc/languages-frameworks/javascript.section.md`
491d3f7e830c5824d312232c06ada2911f68109c1f5aaa500000000100000ffd
Commands like `npm install` & `npm add` that writes packages & executables needs to be used with `--package-lock-only`.

This means `npm` installs dependencies by writing into `package-lock.json` without modifying the `node_modules` folder. Installation happens through reloading the devShell.
This might be best practice since it gives the `nix shell` virtually exclusive ownership over your `node_modules` folder.

It's recommended to set `package-lock-only = true` in your project-local [`.npmrc`](https://docs.npmjs.com/cli/v11/configuring-npm/npmrc).
:::

### corepack {#javascript-corepack}

This package puts the corepack wrappers for pnpm and yarn in your PATH, and they will honor the `packageManager` setting in the `package.json`.

### node2nix {#javascript-node2nix}

#### Preparation {#javascript-node2nix-preparation}

You will need to generate a Nix expression for the dependencies. Don't forget the `-l package-lock.json` if there is a lock file. Most probably you will need the `--development` to include the `devDependencies`

So the command will most likely be:
```sh
node2nix --development -l package-lock.json
```

See `node2nix` [docs](https://github.com/svanderburg/node2nix) for more info.

#### Pitfalls {#javascript-node2nix-pitfalls}

- If upstream package.json does not have a "version" attribute, `node2nix` will crash. You will need to add it like shown in [the package.json section](#javascript-upstream-package-json).
- `node2nix` has some [bugs](https://github.com/svanderburg/node2nix/issues/238) related to working with lock files from npm distributed with `nodejs_16`.
- `node2nix` does not like missing packages from npm. If you see something like `Cannot resolve version: vue-loader-v16@undefined` then you might want to try another tool. The package might have been pulled off of npm.

### pnpm {#javascript-pnpm}

Pnpm is available as the top-level package `pnpm`. Additionally, there are variants pinned to certain major versions, like `pnpm_8` and `pnpm_9`, which support different sets of lock file versions.

When packaging an application that includes a `pnpm-lock.yaml`, you need to fetch the pnpm store for that project using a fixed-output-derivation. The functions `pnpm_8.fetchDeps` and `pnpm_9.fetchDeps` can create this pnpm store derivation. In conjunction, the setup hooks `pnpm_8.configHook` and `pnpm_9.configHook` will prepare the build environment to install the prefetched dependencies store. Here is an example for a package that contains a `package.json` and a `pnpm-lock.yaml` files using the above `pnpm_` attributes:

```nix
{
  stdenv,
  nodejs,
  # This is pinned as { pnpm = pnpm_9; }
  pnpm,
}:

stdenv.mkDerivation (finalAttrs: {
  pname = "foo";
  version = "0-unstable-1980-01-01";

  src = {
    #...
  };

  nativeBuildInputs = [
    nodejs
    pnpm.configHook
  ];

  pnpmDeps = pnpm.fetchDeps {
    inherit (finalAttrs) pname version src;
    hash = "...";
  };
})
```

NOTE: It is highly recommended to use a pinned version of pnpm (i.e. `pnpm_8` or `pnpm_9`), to increase future reproducibility. It might also be required to use an older version, if the package needs support for a certain lock file version.

In case you are patching `package.json` or `pnpm-lock.yaml`, make sure to pass `finalAttrs.patches` to the function as well (i.e. `inherit (finalAttrs) patches`.

`pnpm.configHook` supports adding additional `pnpm install` flags via `pnpmInstallFlags` which can be set to a Nix string array:

```nix
{
  pnpm,
}:

stdenv.mkDerivation (finalAttrs: {
  pname = "foo";
  version = "0-unstable-1980-01-01";

  src = {
    # ...
  };

  pnpmInstallFlags = [ "--shamefully-hoist" ];

  pnpmDeps = pnpm.fetchDeps {
    inherit (finalAttrs) pnpmInstallFlags;
  };
})
```

#### Dealing with `sourceRoot` {#javascript-pnpm-sourceRoot}

If the pnpm project is in a subdirectory, you can just define `sourceRoot` or `setSourceRoot` for `fetchDeps`.
If `sourceRoot` is different between the parent derivation and `fetchDeps`, you will have to set `pnpmRoot` to effectively be the same location as it is in `fetchDeps`.

Title: npm commands, Corepack, Node2nix Details, PNPM
Summary
This section expands on npm usage with `--package-lock-only` for exclusive `node_modules` control. It details Node2nix, covering command usage, documentation links, and potential pitfalls like missing 'version' attributes or incompatibility with certain npm versions. The section then transitions to PNPM, explaining how to use pinned versions like `pnpm_8` and `pnpm_9` along with `fetchDeps` and `configHook` for managing dependencies and setting up the build environment, with examples for adding install flags and dealing with `sourceRoot`.