Nix build fails for specific npm package

Hey, there is one npm package that causes trouble for me when running nix build using buildNpmPackage in my flake.nix file. This package is called sharp, and here is the error message:

error: builder for '/nix/store/59qj7rbv5k376i6f1yhcfqk8pgsw4s4d-build-website.drv' failed with exit code 1;
       last 10 log lines:
       > npm ERR! command sh -c (node install/libvips && node install/dll-copy && prebuild-install) || (node install/can-compile && node-gyp rebuild && node install/dll-copy)
       > npm ERR! sharp: Are you trying to install as a root or sudo user?
       > npm ERR! sharp: - For npm <= v6, try again with the "--unsafe-perm" flag
       > npm ERR! sharp: - For npm >= v8, the user must own the directory "npm install" is run in
       > npm ERR! sharp: Please see https://sharp.pixelplumbing.com/install for required dependencies
       > npm ERR! sharp: Installation error: EACCES: permission denied, mkdir '/nix/store/077qgrp572ck9m32q7r8dcd42rcd7hzr-build-website-npm-deps/_libvips'

I think this error is quite helpful, but unfortunately I do not know how I would overcome this issue.

I will post my flake.nix contents below, it would be much appreciated if you could show me how I have to adjust the flake for this scenario :slight_smile:

{
  description = "JavaScript development environment";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs";
  };

  outputs = { self, nixpkgs }:
    let
      # Systems supported
      allSystems = [
        "x86_64-linux"
        "aarch64-linux"
        "x86_64-darwin"
        "aarch64-darwin"
      ];
      
      forAllSystems = f: nixpkgs.lib.genAttrs allSystems (system: f {
        pkgs = nixpkgs.legacyPackages.${system};
      });
    in
    {
      packages = forAllSystems ({ pkgs }: {
        default = pkgs.buildNpmPackage {
          name = "build-website";
          buildInputs = with pkgs; [
            nodejs_20
          ];
          src = ./.;
          npmDepsHash = "sha256-2AV40Q7Fqfc/rjC2tc5sm7ss4hZ8dV+zaSpgVUANNNg=";
          npmBuild = "npm run build";
          installPhase = ''
            mkdir $out
            cp -r dist/* $out
          '';
        };
      });
    };
}

Sharp compiles against system libraries. I doubt this will work without a more comprehensive dive into the build scripts, but maybe just adding pkgs.vips to buildInputs and pkgs.pkg-config to nativeBuildInputs is enough.

Nope, unfortunately this did not work :frowning:

Figured; can’t have sane builds when using npm.

You can dive into how buildNpmPackage works in detail, or use dream2nix. This is how I do it with dream2nix, though aiui I’m using a now-deprecated API: https://gitea.tlater.net/tlaternet/tlaternet-webserver/src/branch/master/nix/packages.nix#L43

Can I not implement that in an easy way without dream2nix?

We tried the easy way, it didn’t work.

If you want to do this without dream2nix, you will need to dig into what environment sharp’s build system expects, figure out how exactly buildNpmPackage supplies vips and pkg-config, and then deduce why sharp’s build system doesn’t see them.

I would start with looking at the source code for sharp to see how it tries to install vips (yes, it downloads a random binary from the internet, the joys of npm, thankfully we have nix to protect us from such insanity), if I recall correctly it used to have an environment variable which you could set to override what version of vips was used, but that may have been removed since. sharp also can build against system libraries, which is what you want to make it do, so find out what checks it performs to enable that.

Then I would try - through some educated guesswork - adding commands to the installPhase similar to what sharp’s build system does under the hood, until I spot what’s missing. This is a lot of work, and while I often put effort into responses here, it’s a bit too much work for me to do for you right now ;p

Thank you i fixed the issue by just using something else than sharp, no need to overcomplicate everything

1 Like

this is an issue even with appimages via appimage-run :slight_smile: