Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/nix-community/napalm

Support for building npm packages in Nix and lightweight npm registry [maintainer=?]
https://github.com/nix-community/napalm

build hacktoberfest javascript nix npm

Last synced: 3 months ago
JSON representation

Support for building npm packages in Nix and lightweight npm registry [maintainer=?]

Awesome Lists containing this project

README

        

# Napalm

**This project is looking for a new maintainer, [see](https://github.com/nix-community/napalm/issues/67)**

> When faced with a JavaScript codebase, napalm is just what you need.
>
> -- anonymous

## Table of contents

* [Building npm packages in Nix with Napalm](#building-npm-packages-in-nix-with-napalm)
* [Basic Napalm usage](#basic-napalm-usage)
* [Napalm with Nix flakes](#napalm-with-nix-flakes)
* [More complicated scenarios with Napalm](#handling-complicated-scenarios-with-napalm)
* [Custom node.js version](#custom-nodejs-version)
* [Pre/Post Npm hooks](#prepost-npm-hooks)
* [Multiple package locks](#multiple-package-locks)
* [Patching Npm packages](#patching-npm-packages-before-fetching-them-with-npm)
* [Customizing patching mechanism of npm packages](#customizing-patching-mechanism-of-npm-packages)
* [How does it work ?](#how-does-napalm-work-)
* [Napalm - a lightweight npm registry](#napalm---a-lightweight-npm-registry)

## Building npm packages in Nix with Napalm

### Basic Napalm usage

Use the `buildPackage` function provided in the [`default.nix`](./default.nix)
for building npm packages (replace `` with the path to napalm;
with [niv]: `niv add nmattia/napalm`):

``` nix
let
napalm = pkgs.callPackage {};
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:

``` nix
let
napalm = pkgs.callPackage {};
in napalm.buildPackage ./. { packageLock = ; }
```

### 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](#handling-complicated-scenarios-with-napalm) and potentially set the `nixpkgs` input of napalm with `follows`.

#### Example `flake.nix`

```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:

```shell
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`:

```nix
{ napalm, nodejs-16_x, ... }:
napalm.buildPackage ./. {
nodejs = nodejs-16_x;
}
```

#### Example 2

Changing node.js version to some custom version (just an idea):

```nix
{ 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):

```nix
{ 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

```nix
{ 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:

```nix
{ 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

```nix
{ 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`):

1. Napalm loads all `package-lock.json` files and parses them. Then it fetches all specified packages into the Nix Store.
2. (optional) Napalm patches npm packages and stores their output in new location. Then uses this location as default package location in Nix Store.
3. Napalm creates snapshot that consists of packages names, version and paths to locations in Nix Store that contain them.
4. (optional) Napalm patches `package-lock.json` integrity if the packages were patched, so that they will work with `npm install`.
5. 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.
6. Napalm sets up npm so that it thinks `napalm-registry` server is default npm registry server.
7. Napalm overrides npm which allows using custom npm hooks (every time it is called) as well as some other default patching activities.
8. Napalm calls all the npm commands.
9. 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](./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
```

[niv]: https://github.com/nmattia/niv

## Similar projects

- [npmlock2nix](https://github.com/tweag/npmlock2nix)