Packaging with pnpm: vite not found

i’m trying to package a pnpm project and can’t seem to get vite working

relevant section from flake.nix:

frontend = pkgs.stdenvNoCC.mkDerivation (finalAttrs: rec {
          name = "frontend";
          pname = name;
          src = ./.;
          
          nativeBuildInputs = [ pkgs.nodejs pkgs.pnpm.configHook ];
          
          pnpmDepsHash = "sha256-woA5C1airy7eKbk3EP7cggldNFpz+9y68A16QkGrmeA=";
          pnpmDeps = pkgs.pnpm.fetchDeps {
            inherit (finalAttrs) src pname;
            hash = pnpmDepsHash;
          };
          
          postBuild = ''
            ls $src
            cd $src/frontend
            pnpm build
            # mv dist $out
          '';
        });

minimal package.json:

{
	"type": "module",
	"scripts": {
		"dev": "vite",
		"build": "vite build"
	},
	"dependencies": {
		"vite": "^6.1.0"
	}
}

it’s in a subdirectory, as part of a workspace. this is the root dir’s pnpm-workspace.yaml

packages:
  - frontend

it keeps failing with vite: command not found and says node_modules is missing

pnpmConfigHook should run pnpm install for you, so node_modules should hopefully exist. Can you tell if pnpm install process runs?

However, in any case it won’t add node_modules/.bin to PATH automatically, for that, you want something like PATH=$PATH:$PWD/node_modules/.bin before pnpm build. At least that’s what I did for teleport.

pnpm seems to run, but node_modules doesn’t exist. Here are the logs:

Running phase: unpackPhase
@nix { "action": "setPhase", "phase": "unpackPhase" }
unpacking source archive /nix/store/6spjkqsp24mw8mc64nssd3nlwkl3i1xq-2qjm79qqjb970xnwj70mdpwv6wfxvy67-source
source root is 2qjm79qqjb970xnwj70mdpwv6wfxvy67-source
Running phase: patchPhase
@nix { "action": "setPhase", "phase": "patchPhase" }
Running phase: updateAutotoolsGnuConfigScriptsPhase
@nix { "action": "setPhase", "phase": "updateAutotoolsGnuConfigScriptsPhase" }
Running phase: configurePhase
@nix { "action": "setPhase", "phase": "configurePhase" }
Executing pnpmConfigHook
Configuring pnpm store
Installing dependencies
Scope: all 3 workspace projects
Lockfile is up to date, resolution step is skipped
Progress: resolved 1, reused 0, downloaded 0, added 0
Packages: +279

Progress: resolved 1, reused 0, downloaded 0, added 0
Progress: resolved 279, reused 276, downloaded 0, added 47
Progress: resolved 279, reused 279, downloaded 0, added 279, done

devDependencies:
+ typescript 5.7.3

Done in 734ms
Patching scripts
patching script interpreter paths in node_modules/typescript node_modules/.bin node_modules/.modules.yaml node_modules/.pnpm node_modules/.pnpm-workspace-state.json
node_modules/.bin/tsserver: interpreter directive changed from "#!/bin/sh" to "/nix/store/fd118hwh7d1ncib4mdw56ylv3g9k0iyj-bash-5.2p37/bin/sh"
node_modules/.bin/tsc: interpreter directive changed from "#!/bin/sh" to "/nix/store/fd118hwh7d1ncib4mdw56ylv3g9k0iyj-bash-5.2p37/bin/sh"
node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/bin/tsc: interpreter directive changed from "#!/usr/bin/env node" to "/nix/store/i1jdnip70qb7yh4krlzsgyxs0zdvw7xv-nodejs-22.13.1/bin/node"
node_modules/.pnpm/typescript@5.7.3/node_modules/typescript/bin/tsserver: interpreter directive changed from "#!/usr/bin/env node" to "/nix/store/i1jdnip70qb7yh4krlzsgyxs0zdvw7xv-nodejs-22.13.1/bin/node"
node_modules/.pnpm/es5-ext@0.10.64/node_modules/es5-ext/_postinstall.js: interpreter directive changed from "#!/usr/bin/env node" to "/nix/store/i1jdnip70qb7yh4krlzsgyxs0zdvw7xv-nodejs-22.13.1/bin/node"
(lots more "directive changed" lines...)
Finished pnpmConfigHook
Running phase: buildPhase
@nix { "action": "setPhase", "phase": "buildPhase" }

> frontend@ build /nix/store/6spjkqsp24mw8mc64nssd3nlwkl3i1xq-2qjm79qqjb970xnwj70mdpwv6wfxvy67-source/frontend
> vite build

sh: line 1: vite: command not found
 ELIFECYCLE  Command failed.
 WARN   Local package.json exists, but node_modules missing, did you mean to install?

Turns out it was two problems:

First, it didn’t seem to install every dependency. This is fixed by setting pnpmRoot and sourceRoot:

          pnpmRoot = "frontend";
          pnpmDepsHash = "sha256-woA5C1airy7eKbk3EP7cggldNFpz+9y68A16QkGrmeA=";
          pnpmDeps = pkgs.pnpm.fetchDeps {
            inherit (finalAttrs) src pname version;
            hash = pnpmDepsHash;
            sourceRoot = "${finalAttrs.src}/frontend";
          };

Second, cd $src/frontend is wrong because $src is readonly. The source code is already copied to the current directory, so I only need cd frontend.