When I tried build npm package in a subdirectory of the current project, it couldn’t find the directory:
Source:
pkgs.buildNpmPackage {
name = "xxx";
src = ./.;
sourceRoot = "source/cli";
npmDepsHash = "...";
};
Error:
Running phase: unpackPhase
unpacking source archive /nix/store/1ym91argw0z2f1wlcm410ydk4fkmhil9-rr7fi5fifihfxsddxh46bwmrcs1kayqi-source
source root is source/cli
chmod: cannot access 'source/cli': No such file or directory
However, if I build the package from another flake and add this project to its input, it can build without error:
pkgs.buildNpmPackage {
name = "xxx";
src = inputs.my-project;
sourceRoot = "source/cli";
npmDepsHash = "...";
};
Is there a way to build an npm package in a subdirectory within the same project?
The src
needs to refer to the dir that contains the cli
directory.
Also I suggest using "${src.name}/cli"
rather than hardcoding "source/cli"
in the string (just in case the name changes for whichever reason).
If you’re still stuck, please share your code or at least a minimal reproducible example.
source is the the place Nix unpacking the source code. src.name
won’t be available as src
is a path. Besides, using src.name
is a bad idea as it will refer to a read-only path.
I’ll come up with an example soon.
A minimal example is straight forward:
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
};
outputs = inputs@{ nixpkgs, flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
systems = [ "x86_64-linux" "aarch64-linux" ];
perSystem = { self', system, pkgs, lib, ... }: {
packages.default = pkgs.buildNpmPackage {
name = "test";
src = ./.;
sourceRoot = "source/cli";
npmDepsHash = lib.fakeHash;
};
};
};
}
Then just create a directory cli
and run npm init -y && npm i
inside it.
The nix build .
will fail with the same error.
Using $src
would be the readonly store path, that’s different from my suggestion though.
Also I missed that you were using a path, not a fetcher in the first example.
If you simply provide a path, then the path will get unpacked to a dir called [hash]-source
where [hash]
could be anything if you’re using flakes, and if you’re not using flakes, then it takes the name of the current directory (even more impure!)
To fix your issue you probably want to implement something like Working with local files — nix.dev documentation to avoid dependency on the current directory’s name and ensure only the build-relevant files are included.
For example, if you want to exclude result
(if present), default.nix
, flake.nix
, and flake.lock
from the build:
let
fs = lib.fileset;
sourceFiles = fs.difference ./. (
fs.unions [
(fs.maybeMissing ./result)
./default.nix
./flake.nix
./flake.lock
]
);
in
buildNpmPackage rec {
src = fs.toSource {
root = ./.;
fileset = sourceFiles;
};
sourceRoot = "${src.name}/cli";
# other code...
}
Using toSrouce
works perfectly. Thanks for the solution!