diff --git a/doc/languages-frameworks/javascript.section.md b/doc/languages-frameworks/javascript.section.md index 362130e5ba5f..58a0805cc58d 100644 --- a/doc/languages-frameworks/javascript.section.md +++ b/doc/languages-frameworks/javascript.section.md @@ -305,7 +305,7 @@ This package puts the corepack wrappers for pnpm and yarn in your PATH, and they ### pnpm {#javascript-pnpm} -pnpm is available as the top-level package `pnpm`. Additionally, there are variants pinned to certain major versions, like `pnpm_8`, `pnpm_9` and `pnpm_10`, which support different sets of lock file versions. +pnpm is available as the top-level package `pnpm`. Additionally, there are variants pinned to certain major versions, like `pnpm_8`, `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` will prepare the build environment to install the pre-fetched dependencies store. Here is an example for a package that contains `package.json` and a `pnpm-lock.yaml` files using the fetcher and setup hook above: @@ -313,11 +313,18 @@ When packaging an application that includes a `pnpm-lock.yaml`, you need to fetc { fetchPnpmDeps, nodejs, - pnpm, + 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"; @@ -334,54 +341,13 @@ stdenv.mkDerivation (finalAttrs: { pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) pname version src; + inherit pnpm; fetcherVersion = 3; hash = "..."; }; }) ``` -It is highly recommended to use a pinned version of pnpm (i.e., `pnpm_9` or `pnpm_10`), 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. To do so, you can pass the `pnpm` argument to `fetchPnpmDeps` and 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 = nodejs_20; }; -+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 = 3; - 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: diff --git a/pkgs/build-support/node/fetch-pnpm-deps/serve.nix b/pkgs/build-support/node/fetch-pnpm-deps/serve.nix index 9aa5d380a0cd..46288e974660 100644 --- a/pkgs/build-support/node/fetch-pnpm-deps/serve.nix +++ b/pkgs/build-support/node/fetch-pnpm-deps/serve.nix @@ -3,6 +3,7 @@ pnpm, pnpmDeps, zstd, + lib, }: writeShellApplication { @@ -41,4 +42,8 @@ writeShellApplication { pnpm server start \ --store-dir "$storePath" ''; + + meta = { + broken = lib.versionAtLeast pnpm.version "11"; + }; } diff --git a/pkgs/development/tools/pnpm/default.nix b/pkgs/development/tools/pnpm/default.nix index 3975dbc04277..c1423124fc24 100644 --- a/pkgs/development/tools/pnpm/default.nix +++ b/pkgs/development/tools/pnpm/default.nix @@ -25,6 +25,10 @@ let version = "10.33.4"; hash = "sha256-jnDdxmSbGLw9iVzzqQjAKR6kw4A5rYcixH4Bja8enPw="; }; + "11" = { + version = "11.1.0"; + hash = "sha256-VzyCrTVuiwl+bKxIG3OB+d7tM6MYr38xGYSFjr4fl+8="; + }; }; callPnpm = variant: callPackage ./generic.nix { inherit (variant) version hash; }; diff --git a/pkgs/development/tools/pnpm/generic.nix b/pkgs/development/tools/pnpm/generic.nix index 76a0b40835e4..aa50a4fd3a52 100644 --- a/pkgs/development/tools/pnpm/generic.nix +++ b/pkgs/development/tools/pnpm/generic.nix @@ -10,6 +10,7 @@ testers, buildPackages, bashNonInteractive, + tests, withNode ? true, version, @@ -43,16 +44,21 @@ stdenvNoCC.mkDerivation (finalAttrs: { rm -r package/dist/reflink.*node package/dist/vendor ''; - installPhase = '' - runHook preInstall + installPhase = + let + # Use ESM pnpm for versions > 11 + ext = if lib.versionOlder finalAttrs.version "11" then "cjs" else "mjs"; + in + '' + runHook preInstall - install -d $out/{bin,libexec} - cp -R . $out/libexec/pnpm - ln -s $out/libexec/pnpm/bin/pnpm.cjs $out/bin/pnpm - ln -s $out/libexec/pnpm/bin/pnpx.cjs $out/bin/pnpx + install -d $out/{bin,libexec} + cp -R . $out/libexec/pnpm + ln -s $out/libexec/pnpm/bin/pnpm.${ext} $out/bin/pnpm + ln -s $out/libexec/pnpm/bin/pnpx.${ext} $out/bin/pnpx - runHook postInstall - ''; + runHook postInstall + ''; postInstall = if lib.toInt (lib.versions.major version) < 9 then @@ -105,9 +111,10 @@ stdenvNoCC.mkDerivation (finalAttrs: { ); inherit nodejs majorVersion; - tests.version = lib.optionalAttrs withNode ( - testers.testVersion { package = finalAttrs.finalPackage; } - ); + tests = { + inherit (tests) pnpm; + version = lib.optionalAttrs withNode (testers.testVersion { package = finalAttrs.finalPackage; }); + }; updateScript = writeScript "pnpm-update-script" '' #!/usr/bin/env nix-shell #!nix-shell -i bash -p curl jq common-updater-scripts diff --git a/pkgs/test/pnpm/default.nix b/pkgs/test/pnpm/default.nix index 85874ec1a57f..8cc5708ec735 100644 --- a/pkgs/test/pnpm/default.nix +++ b/pkgs/test/pnpm/default.nix @@ -2,4 +2,5 @@ { pnpm-empty-lockfile = callPackage ./pnpm-empty-lockfile { }; pnpm-fixup-state-db = callPackage ./pnpm-fixup-state-db { }; + pnpm_11 = callPackage ./pnpm_11 { }; } diff --git a/pkgs/test/pnpm/pnpm-fixup-state-db/index.db b/pkgs/test/pnpm/pnpm-fixup-state-db/index.db index 705910416a04..aa5dcd007e26 100644 Binary files a/pkgs/test/pnpm/pnpm-fixup-state-db/index.db and b/pkgs/test/pnpm/pnpm-fixup-state-db/index.db differ diff --git a/pkgs/test/pnpm/pnpm_11/default.nix b/pkgs/test/pnpm/pnpm_11/default.nix new file mode 100644 index 000000000000..bf3ab4d4f551 --- /dev/null +++ b/pkgs/test/pnpm/pnpm_11/default.nix @@ -0,0 +1,60 @@ +{ + fetchPnpmDeps, + lib, + makeShellWrapper, + nodejs, + pnpmConfigHook, + pnpm_11, + stdenv, + testers, +}: +let + pnpm = pnpm_11; +in +stdenv.mkDerivation (finalAttrs: { + pname = "pnpm-test"; + inherit (pnpm) version; + + src = ./src; + + pnpmDeps = testers.invalidateFetcherByDrvHash fetchPnpmDeps { + inherit (finalAttrs) pname version src; + inherit pnpm; + fetcherVersion = 3; + hash = "sha256-+Vrv5ZiVIARDZrR5/4OYRmaecQQZmcZFtMjK4qhXKb8="; + }; + + nativeBuildInputs = [ + makeShellWrapper + nodejs + pnpm + pnpmConfigHook + ]; + + buildPhase = '' + runHook preBuild + + pnpm build + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + install -Dm644 -t $out/lib/pnpm-11-test dist/index.js + + makeWrapper ${lib.getExe nodejs} $out/bin/pnpm11test \ + --add-flags "$out/lib/pnpm11test" + + runHook postInstall + ''; + + __structuredAttrs = true; + + meta = { + license = lib.licenses.mit; + mainProgram = "pnpm11test"; + inherit (pnpm.meta) maintainers; + }; +}) diff --git a/pkgs/test/pnpm/pnpm_11/src/.gitignore b/pkgs/test/pnpm/pnpm_11/src/.gitignore new file mode 100644 index 000000000000..1eae0cf6700c --- /dev/null +++ b/pkgs/test/pnpm/pnpm_11/src/.gitignore @@ -0,0 +1,2 @@ +dist/ +node_modules/ diff --git a/pkgs/test/pnpm/pnpm_11/src/index.ts b/pkgs/test/pnpm/pnpm_11/src/index.ts new file mode 100644 index 000000000000..accefceba62b --- /dev/null +++ b/pkgs/test/pnpm/pnpm_11/src/index.ts @@ -0,0 +1 @@ +console.log("Hello World"); diff --git a/pkgs/test/pnpm/pnpm_11/src/package.json b/pkgs/test/pnpm/pnpm_11/src/package.json new file mode 100644 index 000000000000..1eb3b51b3886 --- /dev/null +++ b/pkgs/test/pnpm/pnpm_11/src/package.json @@ -0,0 +1,20 @@ +{ + "name": "pnpm11test", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "build": "tsc", + "start": "node dist/index.js" + }, + "license": "MIT", + "packageManager": "pnpm", + "type": "module", + "files": [ + "dist/" + ], + "devDependencies": { + "@types/node": "^25.5.0", + "typescript": "^6.0.2" + } +} diff --git a/pkgs/test/pnpm/pnpm_11/src/pnpm-lock.yaml b/pkgs/test/pnpm/pnpm_11/src/pnpm-lock.yaml new file mode 100644 index 000000000000..def71aa4e5a2 --- /dev/null +++ b/pkgs/test/pnpm/pnpm_11/src/pnpm-lock.yaml @@ -0,0 +1,39 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@types/node': + specifier: ^25.5.0 + version: 25.5.0 + typescript: + specifier: ^6.0.2 + version: 6.0.2 + +packages: + + '@types/node@25.5.0': + resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} + + typescript@6.0.2: + resolution: {integrity: sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + +snapshots: + + '@types/node@25.5.0': + dependencies: + undici-types: 7.18.2 + + typescript@6.0.2: {} + + undici-types@7.18.2: {} diff --git a/pkgs/test/pnpm/pnpm_11/src/tsconfig.json b/pkgs/test/pnpm/pnpm_11/src/tsconfig.json new file mode 100644 index 000000000000..3471bd329666 --- /dev/null +++ b/pkgs/test/pnpm/pnpm_11/src/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "dist", + "rootDir": ".", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + } +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 0133a2683d37..f864001a47cc 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -3141,8 +3141,9 @@ with pkgs; pnpm_9 pnpm_10_29_2 pnpm_10 + pnpm_11 ; - pnpm = pnpm_10; + pnpm = pnpm_11; inherit (callPackages ../build-support/node/fetch-pnpm-deps { }) fetchPnpmDeps