# How to package Javascript stubs / support code

**URL:** <https://discuss.ocaml.org/t/how-to-package-javascript-stubs-support-code/9111>\
**Category:** Ecosystem\
**Tags:** js\_of\_ocaml, opam, dune\
**Created:** [January 6, 2022, 3:13am UTC](https://discuss.ocaml.org/t/how-to-package-javascript-stubs-support-code/9111 "2022-01-06T03:13:15Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![joelb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/joelb/32/1996_2.png) [@joelb](https://discuss.ocaml.org/u/joelb)\
**Post date:** [January 6, 2022, 3:13am UTC](https://discuss.ocaml.org/t/how-to-package-javascript-stubs-support-code/9111/1 "2022-01-06T03:13:15Z")

</div>

Background: I’m trying to create OCaml (js\_of\_ocaml) bindings to the tree-sitter.js library. My repository is at [GitHub - joelburget/brr-web-tree-sitter: Ocaml (Brr) bindings to web-tree-sitter](https://github.com/joelburget/brr-web-tree-sitter).

Question 1: Reading through the [opam manual](https://opam.ocaml.org/doc/Manual.html), I don’t see any mention of js\_of\_ocaml, minimal mention of stubs, and the document assumes architectures are ’ typically one of `"x86_32"` , `"x86_64"` , `"ppc32"` , `"ppc64"` , `"arm32"` or `"arm64"` , or the lowercased output of `uname -m` , or `"unknown"`'. How does the distribution of js\_of\_ocaml-specific libraries typically work?

I attempted to add the tree-sitter.js library using dune sites in [Work on using dune sites. · joelburget/brr-web-tree-sitter@8354580 · GitHub](https://github.com/joelburget/brr-web-tree-sitter/commit/83545801eab5db75ca06dcbd9148f2059360b7aa). Unfortunately this didn’t work, I believe because js\_of\_ocaml removed the library when [linking](https://ocsigen.org/js_of_ocaml/2.5/manual/linker). Quoting the docs:

> Primitive code must be annotated with the primitive name and primitive requirements. The linker uses these information to only include the primitive actually used in the program and to perform better deadcode elimination.

I attempted to fix this in two different ways in [https://github.com/joelburget/brr-web-tree-sitter/commit/5fdd6ee72cfebd7c9f26a2dbafefcd3a17f87534:](https://github.com/joelburget/brr-web-tree-sitter/commit/5fdd6ee72cfebd7c9f26a2dbafefcd3a17f87534:)

1. Adding a line `joo_global_object.TreeSitter = TreeSitter;` to the end of tree-sitter.js. This didn’t have any effect I could see.
2. Adding `external _tree_sitter_fake_primitive : unit -> unit = "tree_sitter_fake_primitive"`) in.

Unfortunately `dune build` gives:

```auto
Undefined symbols for architecture x86_64:
  "_tree_sitter_fake_primitive", referenced from:
      _caml_builtin_cprim in camlobj2b27a0-2f17c0.o

```

I tried adding `(modes js)` to the library, but get “Error: Unknown value js” (I guess this is only available for executables?).

Question 2: What’s the right way to provide bindings to a JavaScript library on opam? What’s the difference between my library and [GitHub - janestreet/zarith\_stubs\_js: Javascripts stubs for the Zarith library](https://github.com/janestreet/zarith_stubs_js) such that zarith\_stubs\_js works?

---

<div class="post-metadata">

**Author:** ![patricoferris](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/patricoferris/32/3621_2.png) [@patricoferris](https://discuss.ocaml.org/u/patricoferris)\
**Post date:** [January 6, 2022, 2:53pm UTC](https://discuss.ocaml.org/t/how-to-package-javascript-stubs-support-code/9111/2 "2022-01-06T14:53:35Z")

</div>

Hi @joelb,

Quick disclaimer, I haven’t actually _released_ any jsoo bindings to Javascript libraries. But hopefully I can help a bit :))

> [@joelb](#):
>
> Question 1: Reading through the [opam manual](https://opam.ocaml.org/doc/Manual.html), I don’t see any mention of js\_of\_ocaml, minimal mention of stubs, and the document assumes architectures are ’ typically one of `"x86_32"` , `"x86_64"` , `"ppc32"` , `"ppc64"` , `"arm32"` or `"arm64"` , or the lowercased output of `uname -m` , or `"unknown"` '. How does the distribution of js\_of\_ocaml-specific libraries typically work?

I think js\_of\_ocaml support in opam is lacking, I don’t think there is a way to specify that a library should only be used in the context of compiling to javascript. If it is a binding library, it will have a dependency most likely to `js_of_ocaml` but that’s probably about it. There’s nothing in opam yet that I’m aware of to mark a library as jsoo-compatible (by library here I mean plain OCaml code not a binding to a JS library).

> [@joelb](#):
>
> Question 2: What’s the right way to provide bindings to a JavaScript library on opam?

As I see it the current way to do this is just to release the library like any other library. When compiling an actual application with dune using `executable` and `(modes js)`, it is then up to the user to provide the javascript library which could be:

- As a `<script>` tag in the HTML (e.g. see the bindings to C3 as an OCaml library [GitHub - djs55/ocaml-c3: OCaml bindings for the Javascript c3 charting library](https://github.com/djs55/ocaml-c3) and [the example](https://github.com/djs55/ocaml-c3/tree/master/example)), this is probably what your tree-sitter library most closely resembles.
- Using a `.js` file with the `joo_global_object` approach like you pointed out (e.g. [jsoo-code-mirror/example/src/dune at 9cde9873bb540c477fed0fd78772dddc015e97ef · patricoferris/jsoo-code-mirror · GitHub](https://github.com/patricoferris/jsoo-code-mirror/blob/9cde9873bb540c477fed0fd78772dddc015e97ef/example/src/dune#L4-L5))

You could then document how a user should provide the JS library implementation that your library binds.

Alternatively, the `library` stanza does support the `js_of_ocaml` field (see [Stanza Reference — Dune documentation](https://dune.readthedocs.io/en/stable/dune-files.html#jsoo-field)). I believe this allows you to vendor the Javascript library in your repository and link it to the library so the user wouldn’t have to provide it at all. This allows you to write bindings for a specific version of a library and ensure the user gets the correct JS. See for example the bindings to leaflet here: [https://codeberg.org/openEngiadina/geopub/src/branch/main/src/leaflet/dune](https://codeberg.org/openEngiadina/geopub/src/branch/main/src/leaflet/dune). I haven’t actually seen anything released like this in practice, but I think it should work.

> [@joelb](#):
>
> What’s the difference between my library and [GitHub - janestreet/zarith\_stubs\_js: Javascripts stubs for the Zarith library](https://github.com/janestreet/zarith_stubs_js) such that zarith\_stubs\_js works?

The difference is you are binding a Javascript library whereas `zarith_stubs_js` provides Javascript implementations for Zarith’s C functions. For example, the C function [`ml_z_div`](https://github.com/ocaml/Zarith/blob/91eb6e467f110feebdf84685cdf9588b04d64139/caml_z.c#L1604) and the [JS counterpart](https://github.com/janestreet/zarith_stubs_js/blob/04848949cd6d0dd438dc569436b83d3289a66528/runtime.js#L63).

---

<div class="post-metadata">

**Author:** ![joelb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/joelb/32/1996_2.png) [@joelb](https://discuss.ocaml.org/u/joelb)\
**Post date:** [January 6, 2022, 5:09pm UTC](https://discuss.ocaml.org/t/how-to-package-javascript-stubs-support-code/9111/3 "2022-01-06T17:09:36Z")

</div>

Thank you @patricoferris, your answer is very helpful.

> Using a `.js` file with the `joo_global_object` approach like you pointed out

I want to make sure I understand the approach you’re taking here. JSOO outputs `index.bc.js`, which includes `require("@codemirror/view")`, `require("@codemirror/state")`, etc. You then rely on Parcel (or Webpack, etc) to link the JS. Does that sound right?

This approach sounds very appealing since it’s simple on the OCaml side. It made your Codemirror bindings possible (which I [could never figure out how to do](https://discuss.ocaml.org/t/js-of-ocaml-and-javascript-modules/7446)). More generally, it solves the problem of working with JS modules from OCaml. I see two downsides:

1. It’s an extra step for users
2. Makes it possible to link an incompatible version of the JS library (as you noted)

By the way, I noticed @jchavarri debating some of the same questions: [Should jsoo-react vendor react.js? · Issue #104 · ml-in-barcelona/jsoo-react · GitHub](https://github.com/ml-in-barcelona/jsoo-react/issues/104).

---

<div class="post-metadata">

**Author:** ![patricoferris](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/patricoferris/32/3621_2.png) [@patricoferris](https://discuss.ocaml.org/u/patricoferris)\
**Post date:** [January 6, 2022, 5:29pm UTC](https://discuss.ocaml.org/t/how-to-package-javascript-stubs-support-code/9111/4 "2022-01-06T17:29:39Z")

</div>

> [@joelb](#):
>
> I want to make sure I understand the approach you’re taking here. JSOO outputs `index.bc.js` , which includes `require("@codemirror/view")` , `require("@codemirror/state")` , etc. You then rely on Parcel (or Webpack, etc) to link the JS. Does that sound right?

Yep exactly, the examples are broken in that code-mirror repository as you pointed out (thanks for the issue), but they _should_ be working [in this editor application](https://github.com/patricoferris/try-irmin/blob/6d04e5f0c1e3630623a9f1552b2a5be48247d681/docs/dune#L32) using `npx esbuild` in a dune rule.

Thanks for pointing out that jsoo-react issue, I like the comment:

> I guess it all comes down to how “close” to JavaScript ecosystem a project is: for projects leveraging a lot of JS related tooling, using Webpack or other bundler is not a pain (actually helps). But for projects leaning more on OCaml side, with very few JavaScript dependencies, adding bundler is actually overkill.
