Is there a way to get just a package's dependencies from package.json?
I'd like to use node2nix to install all of my web app's dependencies inside of a custom Nix shell. Right now, node2nix supports a few flows for getting close but not quite there:
- You can run
node2nixon a standardpackage.jsonfile, then the resulting set innode-packages.nixhas ashellattribute that points to a derivation for a nix-shell that contains all the dependencies.-
Problem: you're forced to use
node2nix's generated shell, doesn't work with custom shells. Perhaps you could use someoverrideAttrshackery or something, but this isn't a clean approach.
-
Problem: you're forced to use
- You can run
node2nixon a standardpackage.jsonfile, then the resulting set innode-packages.nixhas apackageattribute that points to an NPM package for the whole project, including dependencies.-
Problem: this isn't the same as importing just the dependencies.
NODE_PATHin the generated shell doesn't contain the project's dependencies.
-
Problem: this isn't the same as importing just the dependencies.
- You can run
node2nixon a JSON file that contains an array with all your dependencies in it, and the resulting set innode-packages.nixwill contain each of your dependencies. You can then pass these dependencies intomkShell { buildInputs = [...] }.-
Problem: you need to maintain a file separate from the standard
package.jsonwith just the dependencies in an array.
-
Problem: you need to maintain a file separate from the standard
Ideally, I'd like to run node2nix on a standard package.json and be able to access dependencies and devDependencies as attributes on node-packages.nix. In lieu of that, is there a way to achieve what I'm trying to achieve?
Here's an example of my custom shell.nix:
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
let
nodeEnv = callPackage ./node-env.nix {};
nodePackages = callPackage ./node-packages.nix { inherit nodeEnv; };
in mkShell {
buildInputs = [
nodejs
# other deps
]; # ++ nodePackages.dependencies (???)
}
I've dug into the generated code a bit more and I see a couple of things:
-
node-env.nix'sbuildNodeShelldoes more than just package dependencies and append them tobuildInputs, it also generates a dummypackage.jsonfor the dependencies package that gets generated and setsPATHandNODE_PATHfor the shell to use the NPM dependencies. These features are non-trivial to replicate; i.e., my initial assumption that I could just simply "add tobuildInputs" was wrong. - I can achieve my particular use case by passing
globalBuildInputsto mycallPackageinvocation:
{ pkgs ? import <nixpkgs> {} }:
with pkgs;
let
nodeEnv = callPackage ./node-env.nix {};
nodePackages = callPackage ./node-packages.nix {
globalBuildInputs = [
nodejs # not technically necessary since nodejs gets pulled in anyway
# other deps
];
inherit nodeEnv;
};
in nodePackages.shell
That said, I'm not crazy about extending the shell derivation in this way. The syntax feels inelegant. I would prefer something more modular, like being able to grab a dependencies derivation and handle setting PATH and NODE_PATH in a different way, to exercise a more granular level of control.
EDIT:
I probably should play a bit more with the node2nix before commenting as I'm still discovering more ways to achieve what I wanted by using overrides.
OLD:
I want to second @earksiinni suggestion that it would be much easier for custom development shells but also deployments to have direct access to some partial products of package buildup like sources (to make overrides) or args from node-packages.nix.
@paluh can you share some of your discoveries regarding how to use overrides and what your goals are? Would be great to compile some info on best practices.
@earksiinni
I think I should drop my EDIT from previous comment - I'm stuck with my deployment again :-( Sorry for my previous messy comment.
I also think that your suggestion to expand on a given problem solutions is great. I'm going to try to provide a minimal example of my particular package build problem and discuss this in the context of nix-shell and the final deployment expression and their potential consistency and simplicity.
It may be worth mentioning here that it's pretty non-obvious, but you can access nodePackages.shell.nodeDependencies as a derivation you can throw into a buildInputs or use to set up $PATH or $NODE_PATH directly (as I just discovered and mentioned in https://github.com/svanderburg/node2nix/issues/168#issuecomment-611108882).
Something like this will set up a simple dev shell:
{
devShell = pkgs.mkShell {
buildInputs = with pkgs;
with nodePackages; [
nodejs
node2nix
nodeEnv.shell.nodeDependencies
];
shellHook = ''
export NODE_PATH=${nodeEnv.shell.nodeDependencies}/lib/node_modules
'';
};
}
The nodeEnv should be created like so:
{
nodeEnv = pkgs.callPackage ./default.nix { };
}
YMMV, various npm packages rely on node_modules being in the package root. If you really want to make this work, maybe create a symlink with the shellHook instead of overriding the unreliable NODE_PATH variable, but I imagine it being read-only will annoy some npm packages as well.