Writing JavaScript libs in OCaml?



Hi, I need to write pretty simple lib with cli wrapper for JavaScript/TypeScript projects. It needs to read few files from disk, do some logic and print the output to console. It needs to be npm installable.
I would like to write it in OCaml/Reason but there is the question: what’s the lowest possible dependency and runtime cost for using it from plain JS project? What is the difference of using JSOO/BuckleScript for this?
Do you know any libs written like this?


Hi there. Let me start with a quote from a BuckleScript blog post ( https://bucklescript.github.io/blog/2018/12/05/release-4-0-8 ):

If we ignore the C shims, the BuckleScript runtime is very small, and it is pretty easy for experienced BuckleScript programmers to write runtime-free code which generates standalone JS code. Such code could include supporting curried calling conventions, encoding of OCaml ADT, etc.

In my experience this is true. For example, I wrote a utility script that does a little post-processing of some generated HTML documentation: https://github.com/yawaramin/bs-webapi/blob/80c186bc64b36de5dd7d792e09731a2d8e7ad8f3/src/Yawaramin_BsWebapi/Yawaramin_BsWebapi_OCamldoc.ml

It lists the files in the current directory, and for each HTML file it reads it, processes it, and writes the result back to the same file.

This script targets JavaScript and Node and ignores the BuckleScript runtime. It generates a JS output with no dependencies on anything distributed from bs-platform. I made a conscious choice to do it like that. Here are two examples:

  • A simple example: instead of using the OCaml standard library’s Array.iter (which generates a bs-platform dependency), I used Js.Array.forEach, which directly calls forEach on the array.
  • A slightly more complex example: instead of using Printf.sprintf, I wrote a binding to Node’s util.format() and used that directly. The reason I couldn’t use BuckleScript’s built-in interpolation in that case was that my input string was a regex replacement string that contained numbered captures like $1 and BuckleScript would have tried to find a name $1 in scope and failed.

So yes, you can do it with a little care. Keep checking your output for require(...anything from bs-platform...) and find a way to work around those.


I was wondering is it worth to try and it looks possible now. Thx for the hints.