Bs-platform install

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 so bsb and bsc 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.

3 Likes