···310- `node2nix` has some [bugs](https://github.com/svanderburg/node2nix/issues/238) related to working with lock files from npm distributed with `nodejs_16`.
311- `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.
312000000000000000000000000000000000000000000000000000000000000000313### yarn2nix {#javascript-yarn2nix}
314315#### Preparation {#javascript-yarn2nix-preparation}
···310- `node2nix` has some [bugs](https://github.com/svanderburg/node2nix/issues/238) related to working with lock files from npm distributed with `nodejs_16`.
311- `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.
312313+### pnpm {#javascript-pnpm}
314+315+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.
316+317+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:
318+319+```nix
320+{
321+ stdenv,
322+ nodejs,
323+ # This is pinned as { pnpm = pnpm_9; }
324+ pnpm
325+}:
326+327+stdenv.mkDerivation (finalAttrs: {
328+ pname = "foo";
329+ version = "0-unstable-1980-01-01";
330+331+ src = ...;
332+333+ nativeBuildInputs = [
334+ nodejs
335+ pnpm.configHook
336+ ];
337+338+ pnpmDeps = pnpm.fetchDeps {
339+ inherit (finalAttrs) pname version src;
340+ hash = "...";
341+ };
342+})
343+```
344+345+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.
346+347+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`.
348+349+#### Dealing with `sourceRoot` {#javascript-pnpm-sourceRoot}
350+351+If the pnpm project is in a subdirectory, you can just define `sourceRoot` or `setSourceRoot` for `fetchDeps`. Note, that projects using `pnpm-workspace.yaml` are currently not supported, and will probably not work using this approach.
352+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`.
353+354+Assuming the following directory structure, we can define `sourceRoot` and `pnpmRoot` as follows:
355+356+```
357+.
358+├── frontend
359+│ ├── ...
360+│ ├── package.json
361+│ └── pnpm-lock.yaml
362+└── ...
363+```
364+365+```nix
366+ ...
367+ pnpmDeps = pnpm.fetchDeps {
368+ ...
369+ sourceRoot = "${finalAttrs.src.name}/frontend";
370+ };
371+372+ # by default the working directory is the extracted source
373+ pnpmRoot = "frontend";
374+```
375+376### yarn2nix {#javascript-yarn2nix}
377378#### Preparation {#javascript-yarn2nix-preparation}