# JavaScript {#language-javascript} ## Introduction {#javascript-introduction} Package JavaScript applications with the tools below. ## Tools overview {#javascript-tools-overview} ## General principles {#javascript-general-principles} The principles below are ordered by importance. ### Use the project's Node.js version {#javascript-upstream-node-version} It is often not documented which Node.js version the project uses, but if it is, use the same version when packaging. This can be a problem if the project uses the latest and greatest and you are trying to use an earlier version of Node.js. Some cryptic errors regarding V8 may appear. ### Use the project's package manager and lock file {#javascript-upstream-package-manager} A lock file (package-lock.json, yarn.lock...) is supposed to make reproducible installations of `node_modules` for each tool. Package manager guidelines recommend committing those lock files to the repository. If a particular lock file is present, it is a strong indication of which package manager the project uses. Use a Nix tool that understands the lock file. Using a different tool might give you a hard-to-understand error because different packages have been installed. Using a different tool forces you to commit a lock file to the repository. These files are fairly large, so when packaging for nixpkgs, this approach does not scale well. Exceptions to this rule are: - When you encounter one of the bugs from a Nix tool. In each of the tool-specific instructions, known problems are detailed. If a tool has a problem, try another. You may have to re-create a lock file and commit it to Nixpkgs. - Some lock files contain a particular version of a package that has been pulled off npm for some reason. In that case, you can recreate the lock file (by removing the original and running `npm install`, `yarn`, etc.) and commit this to Nixpkgs. ### Use the project's `package.json` {#javascript-upstream-package-json} Exceptions to this rule are: - Sometimes the project assumes some dependencies are installed globally. Add them to the `package.json` manually (`yarn add xxx` or `npm install xxx`). Run locally installed CLI tools with `npx`, for example `npx postcss`. That is how you call them in the phases. - Sometimes there is a version conflict between some dependency requirements. In that case you can fix a version by removing the `^`. - Sometimes a script in `package.json` does not work as is. It might call a CLI tool that is not available, or `cd` into a directory with a different `package.json`, which is common with workspaces. Read what the script does. Reproduce it in the build phases. For example, a `build` script may call `build:ui` and `build:server` in turn. If one fails, split them into separate steps. ```sh yarn build:ui yarn build:server # OR npm run build:ui npm run build:server ``` When you need to override `package.json`, it is best to use the one from the project and make explicit overrides. Here is an example: ```nix { patchedPackageJSON = final.runCommand "package.json" { } '' ${jq}/bin/jq '.version = "0.4.0" | .devDependencies."@jsdoc/cli" = "^0.2.5" ${sonar-src}/package.json > $out ''; } ``` You still need to commit the modified version of the lock files, but at least the overrides are explicit for everyone to see. ### Use `node_modules` directly {#javascript-using-node_modules} Each tool has an abstraction to build the node_modules (dependencies) directory. You can always use the `stdenv.mkDerivation` with the node_modules to build the package (symlink the node_modules directory and then use the package build command). The `node_modules` abstraction can also be used to build some web framework frontends. For an example of this, see how [plausible](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/pl/plausible/package.nix) is built. Then, when building the frontend, you can symlink the `node_modules` directory. ## Tool-specific instructions {#javascript-tool-specific} ### buildNpmPackage {#javascript-buildNpmPackage} `buildNpmPackage` packages npm-based projects in Nixpkgs without the use of an auto-generated dependencies file. It uses npm's cache. It builds a reproducible cache of the project's dependencies and points npm at it. Here's an example: ```nix { lib, buildNpmPackage, fetchFromGitHub, }: buildNpmPackage (finalAttrs: { pname = "flood"; version = "4.7.0"; src = fetchFromGitHub { owner = "jesec"; repo = "flood"; tag = "v${finalAttrs.version}"; hash = "sha256-BR+ZGkBBfd0dSQqAvujsbgsEPFYw/ThrylxUbOksYxM="; }; npmDepsHash = "sha256-tuEfyePwlOy2/mOPdXbqJskO6IowvAP4DWg8xSZwbJw="; # The prepack script runs the build script, which we'd rather do in the build phase. npmPackFlags = [ "--ignore-scripts" ]; NODE_OPTIONS = "--openssl-legacy-provider"; meta = { description = "Modern web UI for various torrent clients with a Node.js backend and React frontend"; homepage = "https://flood.js.org"; license = lib.licenses.gpl3Only; maintainers = with lib.maintainers; [ winter ]; }; }) ``` In the default `installPhase` set by `buildNpmPackage`, it uses `npm pack --json --dry-run` to decide what files to install. They go in `$out/lib/node_modules/$name/`, where `$name` is the `name` string in the package's `package.json`. Additionally, the `bin` and `man` keys in the source's `package.json` are used to decide what binaries and manpages are supposed to be installed. If these are not defined, `npm pack` may miss some files, and no binaries are produced. #### Arguments {#javascript-buildNpmPackage-arguments} * `npmDepsHash`: The output hash of the dependencies for this project. Can be calculated in advance with [`prefetch-npm-deps`](#javascript-buildNpmPackage-prefetch-npm-deps). * `makeCacheWritable`: Whether to make the cache writable prior to installing dependencies. Don't set this unless npm tries to write to the cache directory, as it can slow down the build. * `npmBuildScript`: The script to run to build the project. Defaults to `"build"`. * []{#javascript-buildNpmPackage-npmWorkspace} `npmWorkspace`: The workspace directory within the project to build and install. * `dontNpmBuild`: Option to disable running the build script. Set to `true` if the package does not have a build script. Defaults to `false`. Alternatively, setting `buildPhase` explicitly also disables this. * `dontNpmInstall`: Option to disable running `npm install`. Defaults to `false`. Alternatively, setting `installPhase` explicitly also disables this. * []{#javascript-buildNpmPackage-npmFlags} `npmFlags`: Flags to pass to all npm commands. * `npmInstallFlags`: Flags to pass to `npm ci`. * `npmBuildFlags`: Flags to pass to `npm run ${npmBuildScript}`. * `npmPackFlags`: Flags to pass to `npm pack`. * `npmPruneFlags`: Flags to pass to `npm prune`. Defaults to the value of `npmInstallFlags`. * `makeWrapperArgs`: Flags to pass to `makeWrapper`, added to executable calling the generated `.js` with `node` as an interpreter. These scripts are defined in `package.json`. * `nodejs`: The `nodejs` package to build against, using the corresponding `npm` shipped with that version of `node`. Defaults to `pkgs.nodejs`. * `npmDeps`: The dependencies used to build the npm package. Especially useful to not have to recompute workspace dependencies. #### prefetch-npm-deps {#javascript-buildNpmPackage-prefetch-npm-deps} `prefetch-npm-deps` is a Nixpkgs package that calculates the hash of the dependencies of an npm project ahead of time. ```console $ ls package.json package-lock.json index.js $ prefetch-npm-deps package-lock.json ... sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= ``` #### fetchNpmDeps {#javascript-buildNpmPackage-fetchNpmDeps} `fetchNpmDeps` is a Nix function that requires the following mandatory arguments: - `src`: A directory or tarball with a `package-lock.json` file - `hash`: The output hash of the dependencies defined in `package-lock.json`. It returns a derivation with all `package-lock.json` dependencies downloaded into `$out/`, usable as an npm cache. #### importNpmLock {#javascript-buildNpmPackage-importNpmLock} This function replaces the npm dependency references in `package.json` and `package-lock.json` with paths to the Nix store. How each dependency is fetched can be customized with the `fetcherOpts` argument. This is a simpler and more convenient alternative to [`fetchNpmDeps`](#javascript-buildNpmPackage-fetchNpmDeps) for managing npm dependencies in Nixpkgs. There is no need to specify a `hash`, since it relies entirely on the integrity hashes already present in the `package-lock.json` file. ##### Inputs {#javascript-buildNpmPackage-inputs} - `npmRoot`: Path to the package directory containing the source tree. If this is omitted, the `package` and `packageLock` arguments must be specified instead. - `package`: Parsed contents of `package.json` - `packageLock`: Parsed contents of `package-lock.json` - `pname`: Package name - `version`: Package version - `fetcherOpts`: An attribute set of arguments forwarded to the underlying fetcher. It returns a derivation with a patched `package.json` and `package-lock.json` with all dependencies resolved to Nix store paths. :::{.note} `npmHooks.npmConfigHook` cannot be used with `importNpmLock`. Use `importNpmLock.npmConfigHook` instead. ::: :::{.example} ##### `pkgs.importNpmLock` usage example {#javascript-buildNpmPackage-example} ```nix { buildNpmPackage, importNpmLock }: buildNpmPackage { pname = "hello"; version = "0.1.0"; src = ./.; npmDeps = importNpmLock { npmRoot = ./.; }; npmConfigHook = importNpmLock.npmConfigHook; } ``` ::: :::{.example} ##### `pkgs.importNpmLock` usage example with `fetcherOpts` {#javascript-buildNpmPackage-example-fetcherOpts} `importNpmLock` uses the following fetchers: - `pkgs.fetchurl` for `http(s)` dependencies - `fetchGit` for `git` dependencies It is possible to provide additional arguments to individual fetchers as needed: ```nix { buildNpmPackage, importNpmLock }: buildNpmPackage { pname = "hello"; version = "0.1.0"; src = ./.; npmDeps = importNpmLock { npmRoot = ./.; fetcherOpts = { # Pass 'curlOptsList' to 'pkgs.fetchurl' while fetching 'axios' "node_modules/axios" = { curlOptsList = [ "--verbose" ]; }; }; }; npmConfigHook = importNpmLock.npmConfigHook; } ``` ::: #### importNpmLock.buildNodeModules {#javascript-buildNpmPackage-importNpmLock.buildNodeModules} `importNpmLock.buildNodeModules` returns a derivation with a pre-built `node_modules` directory, as imported by `importNpmLock`. This is to be used together with `importNpmLock.hooks.linkNodeModulesHook` to support `nix-shell`/`nix develop` development workflows. It accepts an argument with the following attributes: `npmRoot` (Path; optional) : Path to the package directory containing the source tree. If not specified, the `package` and `packageLock` arguments must both be specified. `package` (Attrset; optional) : Parsed contents of `package.json`, as returned by `lib.importJSON ./my-package.json`. If not specified, the `package.json` in `npmRoot` is used. `packageLock` (Attrset; optional) : Parsed contents of `package-lock.json`, as returned by `lib.importJSON ./my-package-lock.json`. If not specified, the `package-lock.json` in `npmRoot` is used. `derivationArgs` (`mkDerivation` attrset; optional) : Arguments passed to `stdenv.mkDerivation` For example: ```nix pkgs.mkShell { packages = [ importNpmLock.hooks.linkNodeModulesHook nodejs ]; npmDeps = importNpmLock.buildNodeModules { npmRoot = ./.; inherit nodejs; }; } ``` creates a development shell where a `node_modules` directory is created and packages are symlinked to the Nix store when activated. :::{.note} Commands like `npm install` and `npm add` that write packages and executables need to be used with `--package-lock-only`. This means `npm` installs dependencies by writing into `package-lock.json` without modifying the `node_modules` folder. It installs by reloading the devShell. This gives the `nix shell` near-exclusive ownership over your `node_modules` folder. 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 honor the `packageManager` setting in the `package.json`. ### pnpm {#javascript-pnpm} pnpm is available as the top-level package `pnpm`. Additionally, there are variants pinned to certain major versions, like `pnpm_9`, `pnpm_10`, `pnpm_10_29_2` and `pnpm_11`, 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 function `fetchPnpmDeps` can create this pnpm store derivation. In conjunction, the setup hook `pnpmConfigHook` prepares the build environment to install the pre-fetched dependencies store. The example below uses the fetcher and setup hook for a package that has `package.json` and `pnpm-lock.yaml`: There is also the [`pnpmBuildHook`](#pnpm-build-hook) for building packages with `pnpm`, as seen in [](#ex-pnpm-build-hook). ```nix { fetchPnpmDeps, nodejs, pnpm_11, pnpmConfigHook, stdenv, }: let # It is recommended to pin pnpm to a major version, due to regular breaking changes in the store format # The latest major version is always available under `pkgs.pnpm` # Optionally override pnpm to use a custom nodejs version # Make sure that the same nodejs version is referenced in nativeBuildInputs # pnpm = pnpm_11.override { nodejs = nodejs_24; }; pnpm = pnpm_11; in stdenv.mkDerivation (finalAttrs: { pname = "foo"; version = "0-unstable-1980-01-01"; src = { #... }; nativeBuildInputs = [ nodejs # in case scripts are run outside of a pnpm call pnpmConfigHook pnpm # At least required by pnpmConfigHook, if not other (custom) phases ]; pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) pname version src; inherit pnpm; fetcherVersion = 4; hash = "..."; }; }) ``` Use a pinned version of pnpm (for example `pnpm_9` or `pnpm_10`) to increase reproducibility. An older version may be required if the package needs a certain lock file version. To do so, pass the `pnpm` argument to `fetchPnpmDeps`. Then override the `pnpm` arg in `pnpmConfigHook`. Here are the changes in the example above to use a pinned pnpm version: ```diff { fetchPnpmDeps, nodejs, - pnpm, + pnpm_10, pnpmConfigHook, stdenv, }: +let + # Optionally override pnpm to use a custom nodejs version + # Make sure that the same nodejs version is referenced in nativeBuildInputs + # pnpm = pnpm_10.override { nodejs-slim = nodejs-slim_22; }; +in stdenv.mkDerivation (finalAttrs: { pname = "foo"; version = "0-unstable-1980-01-01"; src = { #... }; nativeBuildInputs = [ nodejs # in case scripts are run outside of a pnpm call pnpmConfigHook - pnpm # At least required by pnpmConfigHook, if not other (custom) phases + pnpm_10 # At least required by pnpmConfigHook, if not other (custom) phases ]; pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) pname version src; + pnpm = pnpm_10; fetcherVersion = 4; hash = "..."; }; }) ``` 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`). `pnpmConfigHook` supports adding additional `pnpm install` flags via `pnpmInstallFlags` which can be set to a Nix string array: ```nix { # ... pnpmDeps = fetchPnpmDeps { # ... inherit (finalAttrs) pnpmInstallFlags; }; pnpmInstallFlags = [ "--shamefully-hoist" ]; } ``` If needed, set `dontPnpmConfigure = true;` to fully disable `pnpmConfigHook` without removing it from inputs manually. #### Dealing with `sourceRoot` {#javascript-pnpm-sourceRoot} If the pnpm project is in a subdirectory, you can define `sourceRoot` or `setSourceRoot` for `fetchPnpmDeps`. If `sourceRoot` is different between the parent derivation and `fetchPnpmDeps`, you have to set `pnpmRoot` to effectively be the same location as it is in `fetchPnpmDeps`. Assuming the directory structure below, you can define `sourceRoot` and `pnpmRoot`: ``` . ├── frontend │   ├── ... │   ├── package.json │   └── pnpm-lock.yaml └── ... ``` ```nix { # ... pnpmDeps = fetchPnpmDeps { # ... sourceRoot = "${finalAttrs.src.name}/frontend"; }; # by default the working directory is the extracted source pnpmRoot = "frontend"; } ``` #### pnpm workspaces {#javascript-pnpm-workspaces} For a pnpm workspace, set `pnpmWorkspaces = [ "" "" ]` in your `fetchPnpmDeps` call. pnpm then installs only the dependencies for those workspace packages. For example: ```nix { # ... pnpmWorkspaces = [ "@astrojs/language-server" ]; pnpmDeps = fetchPnpmDeps { #... inherit (finalAttrs) pnpmWorkspaces; }; } ``` The above would make `fetchPnpmDeps` call only install dependencies for the `@astrojs/language-server` workspace package. You do not need to set `sourceRoot` to make this work. For these projects, build with `pnpm --filter= build`, because `npmHooks.npmBuildHook` may not work. The example below fits most workspace projects: ```nix { buildPhase = '' runHook preBuild pnpm --filter=@astrojs/language-server build runHook postBuild ''; } ``` #### Additional pnpm commands and settings {#javascript-pnpm-extraCommands} If you require setting an additional pnpm configuration setting (such as `dedupe-peer-dependents` or similar), set `prePnpmInstall` to the right commands to run. For example: ```nix { prePnpmInstall = '' pnpm config set dedupe-peer-dependents false ''; pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) prePnpmInstall; # ... }; } ``` In this example, `prePnpmInstall` runs in both `pnpmConfigHook` and the `fetchPnpmDeps` builder. #### pnpm `fetcherVersion` {#javascript-pnpm-fetcherVersion} This is the version of the output of `fetchPnpmDeps`. Use `4` for new packages: ```nix { # ... pnpmDeps = fetchPnpmDeps { # ... fetcherVersion = 4; hash = "..."; # clear this hash and generate a new one }; } ``` When upgrading to a newer `fetcherVersion`, you need to regenerate the hash. This variable ensures that we can make changes to the output of `fetchPnpmDeps` without breaking existing hashes. Changes can include workarounds or bug fixes to existing pnpm issues. ##### Version history {#javascript-pnpm-fetcherVersion-versionHistory} Version 3 is the minimum supported value. Versions 1 and 2 were removed in the 26.11 release; packages that still use them fail to evaluate and must migrate to `fetcherVersion = 3` (or later) and regenerate their hashes. - 1: Initial version, nothing special. (removed in 26.11) - 2: [Ensure consistent permissions](https://github.com/NixOS/nixpkgs/pull/422975) (removed in 26.11) - 3: [Build a reproducible tarball](https://github.com/NixOS/nixpkgs/pull/469950) - 4: [Dump SQLite database to an SQL file](https://github.com/NixOS/nixpkgs/pull/522703) ### Yarn {#javascript-yarn} Yarn-based projects use a `yarn.lock` file instead of a `package-lock.json` to pin dependencies. To package Yarn-based applications, you need to distinguish by the version pointers in the `yarn.lock` file. See the following sections. #### Yarn v1 {#javascript-yarn-v1} Yarn v1 lockfiles contain a comment `# yarn lockfile v1` at the beginning of the file. Nixpkgs provides the Nix function `fetchYarnDeps` which fetches an offline cache suitable for running `yarn install` before building the project. In addition, Nixpkgs provides the hooks: - `yarnConfigHook`: Fetches the dependencies from the offline cache and installs them into `node_modules`. - `yarnBuildHook`: Runs `yarn build` or a specified `yarn` command that builds the project. - `yarnInstallHook`: Runs `yarn install --production` to prune dependencies and installs the project into `$out`. An example usage of the above attributes is: ```nix { lib, stdenv, fetchFromGitHub, fetchYarnDeps, yarnConfigHook, yarnBuildHook, yarnInstallHook, nodejs, }: stdenv.mkDerivation (finalAttrs: { pname = "..."; version = "..."; src = fetchFromGitHub { owner = "..."; repo = "..."; tag = "v${finalAttrs.version}"; hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; }; yarnOfflineCache = fetchYarnDeps { yarnLock = finalAttrs.src + "/yarn.lock"; hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; }; nativeBuildInputs = [ yarnConfigHook yarnBuildHook yarnInstallHook # Needed for executing package.json scripts nodejs ]; meta = { # ... }; }) ``` ##### `yarnConfigHook` arguments {#javascript-yarnconfighook} By default, `yarnConfigHook` relies upon the attribute `${yarnOfflineCache}` (or `${offlineCache}` if the former is not set) to find the location of the offline cache produced by `fetchYarnDeps`. To disable this phase, you can set `dontYarnInstallDeps = true` or override the `configurePhase`. ##### `yarnBuildHook` arguments {#javascript-yarnbuildhook} This script by default runs `yarn --offline build`, and it relies upon the project's dependencies installed at `node_modules`. Below is a list of additional `mkDerivation` arguments read by this hook: - `yarnBuildScript`: Sets a different `yarn --offline` subcommand (defaults to `build`). - `yarnBuildFlags`: Single string list of additional flags to pass the above command, or a Nix list of such additional flags. ##### `yarnInstallHook` arguments {#javascript-yarninstallhook} To install the package, `yarnInstallHook` uses both `npm` and `yarn` to clean up project files and dependencies. To disable this phase, you can set `dontYarnInstall = true` or override the `installPhase`. Below is a list of additional `mkDerivation` arguments read by this hook: - `yarnKeepDevDeps`: Disables the removal of devDependencies from `node_modules` before installation. #### Yarn Berry v3/v4 {#javascript-yarn-v3-v4} Yarn Berry (v3 / v4) versions have similar formats. They start with blocks like these: ```yaml __metadata: version: 6 cacheKey: 8[cX] ``` ```yaml __metadata: version: 8 cacheKey: 10[cX] ``` For these packages, we have some helpers exposed under the respective `yarn-berry_3` and `yarn-berry_4` packages: - `yarn-berry-fetcher` - `fetchYarnBerryDeps` - `yarnBerryConfigHook` Explicitly pin the major version. For example, capture the `yarn-berry_Xn` argument and re-define it as a `yarn-berry` `let` binding. ```nix { stdenv, nodejs, yarn-berry_4, }: let yarn-berry = yarn-berry_4; in stdenv.mkDerivation (finalAttrs: { pname = "foo"; version = "0-unstable-1980-01-01"; src = { #... }; nativeBuildInputs = [ nodejs yarn-berry.yarnBerryConfigHook ]; offlineCache = yarn-berry.fetchYarnBerryDeps { inherit (finalAttrs) src; hash = "..."; }; }) ``` ##### `yarn-berry_X.fetchYarnBerryDeps` {#javascript-fetchYarnBerryDeps} `fetchYarnBerryDeps` runs `yarn-berry-fetcher fetch` in a fixed-output-derivation. It is a custom fetcher designed to reproducibly download all files in the `yarn.lock` file, validating their hashes in the process. For git dependencies, it creates a checkout at `${offlineCache}/checkouts/<40-character-commit-hash>` (relying on the git commit hash to describe the contents of the checkout). To produce the `hash` argument for the `fetchYarnBerryDeps` call, run `yarn-berry-fetcher prefetch`: ```console $ yarn-berry-fetcher prefetch [/path/to/missing-hashes.json] ``` This prints the hash to stdout. Use it in update scripts to recalculate the hash for a new `yarn.lock`. ##### `yarn-berry_X.yarnBerryConfigHook` {#javascript-yarnBerryConfigHook} `yarnBerryConfigHook` uses the store path `offlineCache` points to, to run a `yarn install` during the build, producing a usable `node_modules` directory from the downloaded dependencies. Internally, this uses a patched version of Yarn to ensure git dependencies are re-packed and any attempted downloads fail immediately. ##### Patching the project's `package.json` or `yarn.lock` files {#javascript-yarnBerry-patching} In case patching the project's `package.json` or `yarn.lock` is needed, it's important to pass `finalAttrs.patches` to `fetchYarnBerryDeps` as well, so the patched variants are picked up (i.e., `inherit (finalAttrs) patches`). ##### Missing hashes in the `yarn.lock` file {#javascript-yarnBerry-missing-hashes} Unfortunately, `yarn.lock` files do not include hashes for optional/platform-specific dependencies. This is [by design](https://github.com/yarnpkg/berry/issues/6759). To compensate for this, run the `yarn-berry-fetcher missing-hashes` subcommand to produce all missing hashes. These are stored in a `missing-hashes.json` file, which needs to be passed to both the build itself, as well as the `fetchYarnBerryDeps` helper: ```nix { stdenv, nodejs, yarn-berry_4, }: let yarn-berry = yarn-berry_4; in stdenv.mkDerivation (finalAttrs: { pname = "foo"; version = "0-unstable-1980-01-01"; src = { #... }; nativeBuildInputs = [ nodejs yarn-berry.yarnBerryConfigHook ]; missingHashes = ./missing-hashes.json; offlineCache = yarn-berry.fetchYarnBerryDeps { inherit (finalAttrs) src missingHashes; hash = "..."; }; }) ``` ## Outside Nixpkgs {#javascript-outside-nixpkgs} There are some other tools available, which are written in the Nix language. These can't be used inside Nixpkgs because they require [Import From Derivation](#ssec-import-from-derivation), which is not allowed in Nixpkgs. If you are packaging something outside Nixpkgs, consider the following: ### npmlock2nix {#javascript-npmlock2nix} [npmlock2nix](https://github.com/nix-community/npmlock2nix) aims at building `node_modules` without code generation. It hasn't reached v1 yet; the API may change. #### Pitfalls {#javascript-npmlock2nix-pitfalls} There are some [problems with npm v7](https://github.com/tweag/npmlock2nix/issues/45). ### nix-npm-buildpackage {#javascript-nix-npm-buildpackage} [nix-npm-buildpackage](https://github.com/serokell/nix-npm-buildpackage) aims at building `node_modules` without code generation. It hasn't reached v1 yet; the API may change. It supports both `package-lock.json` and yarn.lock. #### Pitfalls {#javascript-nix-npm-buildpackage-pitfalls} There are some [problems with npm v7](https://github.com/serokell/nix-npm-buildpackage/issues/33).