diff --git a/doc/hooks/pnpm.section.md b/doc/hooks/pnpm.section.md deleted file mode 100644 index e8871c6c2398..000000000000 --- a/doc/hooks/pnpm.section.md +++ /dev/null @@ -1,142 +0,0 @@ -# pnpmBuildHook {#pnpm-build-hook} - -[pnpm](https://pnpm.io/) is a an NPM-compatible package manager focused on increasing managment speeds, and reducing disk space. - -The `pnpmBuildHook` in Nixpkgs overrides the default build phase for building packages that use pnpm. - -:::{.example #ex-pnpm-build-hook} -## pnpmBuildHook example code snippet {#pnpm-build-hook-code-snippet} - -```nix -{ - lib, - stdenv, - fetchFromGitHub, - fetchPnpmDeps, - pnpmConfigHook, - pnpmBuildHook, - makeBinaryWrapper, - pnpm_10, -}: -let - pnpm = pnpm_10; -in -stdenv.mkDerivation (finalAttrs: { - pname = "coolPackages"; - version = "1.0"; - - src = fetchFromGitHub { - owner = "JaneCool"; - repo = "coolpackage"; - tag = finalAttrs.version; - hash = lib.fakeHash; - }; - - __structuredAttrs = true; - strictDeps = true; - - pnpmDeps = fetchPnpmDeps { - inherit (finalAttrs) pname version src; - inherit pnpm; - fetcherVersion = 4; - hash = lib.fakeHash; - }; - - nativeBuildInputs = [ - pnpmConfigHook - pnpmBuildHook - makeBinaryWrapper - ]; - - pnpmBuildScript = "build"; - pnpmBuildFlags = [ - "--mode" - "production" - ]; - pnpmWorkspaces = [ - "test" - ]; - - installPhase = '' - runHook preInstall - - mkdir "$out" - cp -r dist/. "$out" - - runHook postInstall - ''; - - meta = { - description = "very cool package that does cool things"; - mainProgram = "cool"; - }; -}) -``` -::: - -## Variables controlling pnpmBuildHook {#pnpm-build-hook-variables} - -### pnpm Exclusive Variables {#pnpm-build-hook-exclusive-variables} - -#### `pnpmBuildScript` {#pnpm-build-hook-script} - -Controls the script ran to build the package, by default the script is `build`. - -#### `pnpmFlags` {#pnpm-build-hook-flags} - -Controls flags used for all invocations of pnpm across all hooks local to this derivation. - -#### `pnpmBuildFlags` {#pnpm-build-hook-build-flags} - -Controls the flags pass only to the pnpm build script invocation. - -#### `dontPnpmBuild` {#pnpm-build-hook-dont} - -Disables automatically running `pnpmBuildHook`. The build can still be run manually if needed, for example: - -```nix -{ - lib, - rustPlatform, - pnpmBuildHook, - pnpmConfigHook, - fetchPnpmDeps, - emptyDirectory, - pnpm_10, -}: -let - pnpm = pnpm_10; -in -rustPlatform.buildRustPackage (finalAttrs: { - pname = "super-fast-application"; - version = "1.0"; - - src = emptyDirectory; - - cargoHash = lib.fakeHash; - - nativeBuildInputs = [ - pnpmBuildHook - pnpmConfigHook - ]; - - pnpmDeps = fetchPnpmDeps { - inherit (finalAttrs) pname version src; - inherit pnpm; - fetcherVersion = 4; - hash = lib.fakeHash; - }; - - dontPnpmBuild = true; - postBuild = '' - pnpmBuildHook - ''; -}) -``` - -### Honored Variables {#pnpm-build-hook-honored-variables} - -The following variables are honored by `pnpmBuildHook`. - -* [`pnpmRoot`](#javascript-pnpm-sourceRoot) -* [`pnpmWorkspaces`](#javascript-pnpm-workspaces) diff --git a/doc/languages-frameworks/javascript.section.md b/doc/languages-frameworks/javascript.section.md index 8fd33230573a..ed1cf59945ac 100644 --- a/doc/languages-frameworks/javascript.section.md +++ b/doc/languages-frameworks/javascript.section.md @@ -6,6 +6,12 @@ Package JavaScript applications with the tools below. ## Tools overview {#javascript-tools-overview} +- **npm**: [`buildNpmPackage`](#javascript-buildNpmPackage), [`prefetch-npm-deps` (CLI)](#javascript-buildNpmPackage-prefetch-npm-deps), [`fetchNpmDeps`](#javascript-buildNpmPackage-fetchNpmDeps), [`importNpmLock`](#javascript-buildNpmPackage-importNpmLock) +- [**corepack**](#javascript-corepack) +- **pnpm**: [`fetchPnpmDeps`](#javascript-pnpm), [`pnpmConfigHook`](#javascript-pnpm-pnpmConfigHook), [`pnpmBuildHook`](#javascript-pnpm-pnpmBuildHook) +- [**Yarn v1**](#javascript-yarn-v1): [`fetchYarnDeps`](#javascript-fetchyarndeps), [`yarnConfigHook`](#javascript-yarnconfighook), [`yarnBuildHook`](#javascript-yarnbuildhook), [`yarnInstallHook`](#javascript-yarninstallhook) +- [**Yarn Berry (v3/v4)**](#javascript-yarn-v3-v4): [`fetchYarnBerryDeps`](#javascript-fetchYarnBerryDeps), [`yarnBerryConfigHook`](#javascript-yarnBerryConfigHook) + ## General principles {#javascript-general-principles} The principles below are ordered by importance. @@ -288,9 +294,7 @@ This package puts the corepack wrappers for pnpm and yarn in your PATH, and they 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). +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`](#javascript-pnpm-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`: ```nix { @@ -298,6 +302,7 @@ There is also the [`pnpmBuildHook`](#pnpm-build-hook) for building packages with nodejs, pnpm_11, pnpmConfigHook, + pnpmBuildHook, stdenv, }: let @@ -319,7 +324,8 @@ stdenv.mkDerivation (finalAttrs: { nativeBuildInputs = [ nodejs # in case scripts are run outside of a pnpm call pnpmConfigHook - pnpm # At least required by pnpmConfigHook, if not other (custom) phases + pnpmBuildHook + pnpm # At least required by pnpmConfigHook and pnpmBuildHook, if not other (custom) phases ]; pnpmDeps = fetchPnpmDeps { @@ -331,49 +337,11 @@ stdenv.mkDerivation (finalAttrs: { }) ``` -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: +The example also uses [`pnpmBuildHook`](#javascript-pnpm-pnpmBuildHook), which runs `pnpm run build` in the build phase. - +In case you are patching `package.json` or `pnpm-lock.yaml`, make sure to pass `finalAttrs.patches` to the `fetchPnpmDeps` function as well (i.e., `inherit (finalAttrs) patches`). -```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 {#javascript-pnpm-pnpmConfigHook} `pnpmConfigHook` supports adding additional `pnpm install` flags via `pnpmInstallFlags` which can be set to a Nix string array: @@ -391,6 +359,33 @@ In case you are patching `package.json` or `pnpm-lock.yaml`, make sure to pass ` If needed, set `dontPnpmConfigure = true;` to fully disable `pnpmConfigHook` without removing it from inputs manually. +#### pnpmBuildHook {#javascript-pnpm-pnpmBuildHook} + +The `pnpmBuildHook` in overrides the default build phase with `pnpm run `. + +```nix +{ + nativeBuildInputs = [ + pnpmBuildHook + ]; + + pnpmBuildScript = "build-ui"; + pnpmBuildFlags = [ + "--mode" + "production" + ]; +} +``` + +Available options: + +- `pnpmBuildScript`: select which script from `package.json` to run. Defaults to `build`. +- `pnpmBuildFlags`: array of flags to pass to the build script. +- `pnpmFlags`: currently the same as `pnpmBuildFlags`, but might be used by other hooks in the future. +- `dontPnpmBuild`: disable this hook from running automatically. The hook can still be invoked manually. + +Both [`pnpmRoot`](#javascript-pnpm-sourceRoot) and [`pnpmWorkspaces`](#javascript-pnpm-workspaces) are honored by this hook. + #### Dealing with `sourceRoot` {#javascript-pnpm-sourceRoot} If the pnpm project is in a subdirectory, you can define `sourceRoot` or `setSourceRoot` for `fetchPnpmDeps`. @@ -603,13 +598,8 @@ To install the package, `yarnInstallHook` uses both `npm` and `yarn` to clean up - `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] -``` +Yarn Berry (v3 / v4) versions have similar formats. The `yarn.lock` file starts with blocks like these: ```yaml __metadata: @@ -634,7 +624,6 @@ Explicitly pin the major version. For example, capture the `yarn-berry_Xn` argum let yarn-berry = yarn-berry_4; - in stdenv.mkDerivation (finalAttrs: { pname = "foo"; @@ -657,6 +646,7 @@ stdenv.mkDerivation (finalAttrs: { ``` ##### `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`: @@ -668,14 +658,17 @@ $ 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: @@ -689,7 +682,6 @@ To compensate for this, run the `yarn-berry-fetcher missing-hashes` subcommand t let yarn-berry = yarn-berry_4; - in stdenv.mkDerivation (finalAttrs: { pname = "foo"; diff --git a/doc/nav.json b/doc/nav.json index cc361e87593f..4fd503ed9d8f 100644 --- a/doc/nav.json +++ b/doc/nav.json @@ -430,9 +430,6 @@ { "file": "hooks/pkg-config.section.md" }, - { - "file": "hooks/pnpm.section.md" - }, { "file": "hooks/postgresql-test-hook.section.md" }, diff --git a/doc/redirects.json b/doc/redirects.json index 7050590f58c0..6e62c5579315 100644 --- a/doc/redirects.json +++ b/doc/redirects.json @@ -128,9 +128,6 @@ "ex-pkgs-replace-vars-with": [ "index.html#ex-pkgs-replace-vars-with" ], - "ex-pnpm-build-hook": [ - "index.html#ex-pnpm-build-hook" - ], "ex-shfmt": [ "index.html#ex-shfmt" ], @@ -406,33 +403,6 @@ "pkgs.treefmt.withConfig": [ "index.html#pkgs.treefmt.withConfig" ], - "pnpm-build-hook": [ - "index.html#pnpm-build-hook" - ], - "pnpm-build-hook-build-flags": [ - "index.html#pnpm-build-hook-build-flags" - ], - "pnpm-build-hook-code-snippet": [ - "index.html#pnpm-build-hook-code-snippet" - ], - "pnpm-build-hook-dont": [ - "index.html#pnpm-build-hook-dont" - ], - "pnpm-build-hook-exclusive-variables": [ - "index.html#pnpm-build-hook-exclusive-variables" - ], - "pnpm-build-hook-flags": [ - "index.html#pnpm-build-hook-flags" - ], - "pnpm-build-hook-script": [ - "index.html#pnpm-build-hook-script" - ], - "pnpm-build-hook-variables": [ - "index.html#pnpm-build-hook-variables" - ], - "pnpm-build-hook-honored-variables": [ - "index.html#pnpm-build-hook-honored-variables" - ], "preface": [ "index.html#preface", "index.html#overview-of-nixpkgs" @@ -3886,7 +3856,23 @@ "index.html#javascript-corepack" ], "javascript-pnpm": [ - "index.html#javascript-pnpm" + "index.html#javascript-pnpm", + "index.html#ex-pnpm-build-hook" + ], + "javascript-pnpm-pnpmBuildHook": [ + "index.html#javascript-pnpm-pnpmBuildHook", + "index.html#pnpm-build-hook", + "index.html#pnpm-build-hook-build-flags", + "index.html#pnpm-build-hook-code-snippet", + "index.html#pnpm-build-hook-dont", + "index.html#pnpm-build-hook-exclusive-variables", + "index.html#pnpm-build-hook-flags", + "index.html#pnpm-build-hook-script", + "index.html#pnpm-build-hook-variables", + "index.html#pnpm-build-hook-honored-variables" + ], + "javascript-pnpm-pnpmConfigHook": [ + "index.html#javascript-pnpm-pnpmConfigHook" ], "javascript-pnpm-sourceRoot": [ "index.html#javascript-pnpm-sourceRoot"