Awesome
Napalm
This project is looking for a new maintainer, see
When faced with a JavaScript codebase, napalm is just what you need.
-- anonymous
Table of contents
- Building npm packages in Nix with Napalm
- More complicated scenarios with Napalm
- How does it work ?
- Napalm - a lightweight npm registry
Building npm packages in Nix with Napalm
Basic Napalm usage
Use the buildPackage
function provided in the default.nix
for building npm packages (replace <napalm>
with the path to napalm;
with niv: niv add nmattia/napalm
):
let
napalm = pkgs.callPackage <napalm> {};
in napalm.buildPackage ./. {}
All executables provided by the npm package will be available in the
derivation's bin
directory.
NOTE: napalm uses the package's package-lock.json
(or
npm-shrinkwrap.json
) for building a package database. Make sure there is
either a package-lock.json
or npm-shrinkwrap.json
in the source.
Alternatively provide the path to the package-lock file:
let
napalm = pkgs.callPackage <napalm> {};
in napalm.buildPackage ./. { packageLock = <path/to/package-lock>; }
Napalm with Nix flakes
If you want to use Napalm in your flake project, you can do that by adding it to your inputs and either passing napalm.overlays.default
to your Nixpkgs instance, or by using the napalm.legacyPackages
buildPackage
output. To configure the latter's environment, be sure to look at the complicated scenarios and potentially set the nixpkgs
input of napalm with follows
.
Example flake.nix
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
inputs.napalm.url = "github:nix-community/napalm";
# NOTE: This is optional, but is how to configure napalm's env
inputs.napalm.inputs.nixpkgs.follows = "nixpkgs";
outputs = { self, nixpkgs, napalm }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages."${system}";
in {
# Assuming the flake is in the same directory as package-lock.json
packages."${system}".package-name = napalm.legacyPackages."${system}".buildPackage ./. { };
devShells."${system}".shell-name = pkgs.mkShell {
nativeBuildInputs = with pkgs; [ nodejs ];
};
};
}
Flake Template
There is also a template that can help you use napalm in your project. You can use it in a new, empty directory by running:
nix flake init -t "github:nix-community/napalm"
Handling complicated scenarios with Napalm
Examples below assume that you have imported napalm
in some way.
Custom node.js version
Napalm makes it quite simple to use custom node.js (with npm) version.
This is controlled via nodejs
argument.
Example 1
Changing node.js version to the one that is supplied in nixpkgs
:
{ napalm, nodejs-16_x, ... }:
napalm.buildPackage ./. {
nodejs = nodejs-16_x;
}
Example 2
Changing node.js version to some custom version (just an idea):
{ napalm, nodejs-12_x, ... }:
let
nodejs = nodejs-12_x.overrideAttrs (old: rec {
pname = "nodejs";
version = "12.19.0";
sha256 = "1qainpkakkl3xip9xz2wbs74g95gvc6125cc05z6vyckqi2iqrrv";
name = "${pname}-${version}";
src = builtins.fetchurl {
url =
"https://nodejs.org/dist/v${version}/node-v${version}.tar.xz";
inherit sha256;
};
});
in
napalm.buildPackage ./. {
inherit nodejs;
}
Pre/Post Npm hooks
Napalm allows to specify commands that are run before and after every npm
call.
These hooks work also for nested npm
calls thanks to npm override mechanism.
Example
Patching some folder with executable scripts containing shebangs (that may be generated by npm script):
{ napalm, ... }:
napalm.buildPackage ./. {
postNpmHook = ''
patchShebangs tools
'';
}
Multiple package locks
Napalms allows to specify multiple package locks. This may be useful for some project which consist of some smaller projects.
Example
{ napalm, ... }:
napalm.buildPackage ./. {
# package-lock.json that is in the root of the project
# is not required to be specified in `additionalpackagelocks`
# If you want to specify it, you can use `packageLock` argument.
additionalPackageLocks = [
./frontend/package-lock.json
./tests/package-lock.json
];
}
Patching npm packages (before fetching them with npm)
This is very useful for errors like: Invalid interpreter
Napalm has an ability to patch fetched npm packages before serving them to the npm.
By default patching fixes shebangs and binaries that are localized and the tarballs.
Napalm also updates package-lock.json
with new integrity
hashes.
Example
To enable patching, just use:
{ napalm, ... }:
napalm.buildPackage ./. {
patchPackages = true;
}
This will force repacking of all dependencies, though, so you might want to patch only specific dependencies by passing an empty attribute set to the next method.
Customizing patching mechanism of npm packages
Sometimes it is required to manually patch some package.
Napalm allows that via customPatchPackages
attribute.
This attribute is a set of that overrides for packages that will be patched.
Example
{ napalm, ... }:
napalm.buildPackage ./. {
# Arguments that are passed to the overrider:
# `pkgs` - Nixpkgs used by Napalm
# `prev` - Current set that will be passed to mkDerivation
customPatchPackages = {
"react-native" = {
"0.65.0" = pkgs: prev: {
EXAMPLE_ENV_VAR = "XYZ";
dontBuild = false;
buildPhase = ''
# You can copy some stuff here or run some custom stuff
'';
};
};
# Version is not required. When it is not specified it
# applies override to all packages with that name.
"node-gyp-builder" = pkgs: prev: { };
};
}
How does Napalm work ?
These are general steps that Napalm makes when building packages (if you want to learn more, see source code of default.nix
):
- Napalm loads all
package-lock.json
files and parses them. Then it fetches all specified packages into the Nix Store. - (optional) Napalm patches npm packages and stores their output in new location. Then uses this location as default package location in Nix Store.
- Napalm creates snapshot that consists of packages names, version and paths to locations in Nix Store that contain them.
- (optional) Napalm patches
package-lock.json
integrity if the packages were patched, so that they will work withnpm install
. - Napalm sets up
napalm-registry
which as a main argument accepts snapshot of npm packages and them serves them as if it was npm registry server. - Napalm sets up npm so that it thinks
napalm-registry
server is default npm registry server. - Napalm overrides npm which allows using custom npm hooks (every time it is called) as well as some other default patching activities.
- Napalm calls all the npm commands.
- Napalm installs everything automatically or based on what was specified in
installPhase
.
Napalm - a lightweight npm registry
Under the hood napalm uses its own package registry. The registry is available
in default.nix as napalm-registry
.
Usage: napalm-registry [-v|--verbose] [--endpoint ARG] [--port ARG] --snapshot ARG
Available options:
-v,--verbose Print information about requests
--endpoint ARG The endpoint of this server, used in the Tarball URL
--port ARG The to serve on, also used in the Tarball URL
--snapshot ARG Path to the snapshot file. The snapshot is a JSON
file. The top-level keys are the package names. The
top-level values are objects mapping from version to
the path of the package tarball. Example: { "lodash":
{ "1.0.0": "/path/to/lodash-1.0.0.tgz" } }
-h,--help Show this help text