For the record and anyone who was searching, I was able to get a very complete copy of BuckleScript working with NPM dependencies.
First, use node2nix
to generate the expressions from a list containing the packages you want:
$ cat node-packages.json
[ "bs-platform", "request", "cloudflare" ]
$ nix run nixpkgs.nodePackages.node2nix -c \
node2nix --nodejs-10 -i node-packages.json
This writes out a bunch of files, including a default.nix
which you can import. You can also do some overrides and whatnot. BuckleScript needs a few fixes, mostly to improve build times (to a minute or two):
- Reuse a pre-built copy of
ninja
instead of the vendored version. - Reuse an existing copy of the OCaml compiler
- Fix up the paths to
node_modules
sobsb
andbsc
can find their own libraries, etc.
It comes out looking like this:
let
nodejs = pkgs."nodejs-10_x";
myNodePackages =
let np = import ./nix/bs-platform.nix { inherit pkgs system nodejs; };
in np // {
bs-platform = np.bs-platform.override {
# Fix paths so we can use a cached Ninja, instead of compiling it
preRebuild = ''
substituteInPlace ./scripts/install.js \
--replace "var ninja_bin_output = path.join(root_dir, 'lib', 'ninja.exe')" \
"var ninja_bin_output = '${pkgs.ninja}/bin/ninja'"
substituteInPlace ./lib/bsb.ml \
--replace 'bsc_dir // "ninja.exe"' \
'"${pkgs.ninja}/bin/ninja"'
'';
# This ensures we don't have to link node_modules into CWD. Makes it
# easier to use in nix-shell, or iteratively from ./result, etc
postInstall = ''
wrapProgram $out/bin/bsb --prefix npm_config_prefix : $out
wrapProgram $out/bin/bsc --prefix npm_config_prefix : $out
'';
# Use cached ocaml compiler, instead of recompiling one
buildInputs = with pkgs.ocaml-ng.ocamlPackages_4_02;
[ ocaml merlin pkgs.makeWrapper ];
};
};
Then you can just use myNodePackages.bs-platform
and the BuckleScript compiler will be under $out/bin/bsc
, etc. I’ve tested BSB, etc all work.
You also probably want a way to include Node packages, though, like I do. For that, you can use pkgs.buildEnv
and pkgs.writers.writeBash
to write a wrapper:
myNodeEnv = pkgs.buildEnv {
name = "node-env";
paths = with myNodePackages; [ bs-platform request cloudflare ];
pathsToLink = [ "/lib/node_modules" ];
};
myNode = pkgs.writers.writeBash "node" ''
export NODE_PATH=${myNodeEnv}/lib/node_modules
exec ${nodejs}/bin/node "$@"
'';
Now, myNode
is a copy of node
that has the packages I asked for in node-packages.json
available. In practice all I do is invoke bsb
and copy the resulting .js
files somewhere, and use myNode
as an interpreter for them, which includes everything.