Could merlin be compiled with js_of_ocaml and work in the browser

As the title asks: could merlin be compiled with js_of_ocaml and work in the browser? Has anyone attempted it?

Background: we’d like to make a real web only editor for simple ocaml projects. The features we are looking to provide with merlin is acurate type aware completion and display of module signatures.

1 Like

Yes! See the great work here: GitHub - voodoos/merlin-js with an example Merlin the web. I’ve used it with Try Eio too.


Great! Thanks for the information. I will use those as examples in building our project.

1 Like

Not only is this extremely cool all by itself, it looks to be a perfect demonstration/example of extending codemirror to support a custom language, with a lot of the bells and whistles one would expect, and all via OCaml and jsoo. Outstanding!

1 Like

Is it possible to add a shortcut for “eval -buffer” which sends this all to the jsoo top level ? :slight_smile:

Thank you, glad you like it! We’ve ended up where we are thanks to various bits of hacking from @tmattio, @jonludlam, @voodoos (and I’m sure others!) and of course the jsoo contributors. This is how the playground works (although I think it lost merlin.js in the switch to OCaml 5).

Another nice feature (thanks to @jonludlam!) that might not be immediately apparent is that all of the OCaml evaluation is happening in a browser worker meaning it never blocks the UI (the adventurous can try while true do () done ^^), which has nice story if we compiled notebook style exercises to the browser or something like that.


Hmm not quite sure what you mean, but it sounds like just changing what triggers the evaluation (currently hitting the run button). So it definitely sounds doable :))

I’m an idiot. I was so blown away by the “Merlin the web” demo, I did not even see the “Try EIO” demo. Something else I don’t see – a LICENSE file, what license is “Try EIO” released under ?

@patricoferris : This might come off as naive. Would it be possible to modify this so we can run js_of_ocaml/ at master · ocsigen/js_of_ocaml · GitHub directly in browser in repl, without first compiling it to js on the desktop ?

EDIT: In particular, I’d like to be able to copy/paste that file into Try Eio editor, and hit run.

License is in there now :+1:

Not naive at all, and yes (sort of)! You will need to build the JS files again, but it amounts to only changing dune files and some cmis – in particular:

I seem to remember a plan when we were hacking on this to one day have one of these top-levels for every OCaml Packages · Browse Community Packages (or at least those that compile to jsoo).

1 Like

If the toplevel runs in a webworker, I don’t thing the webgl example will be able to run

How are you deploying the Try Eio site? I noted it is also using 5.0.0~beta1

Hmm yes that sounds right, in which case the top-level worker will need to move to have DOM access, the merlin worker can probably stay in a worker.

By hand ^^ Things just get copied into a docs directory and Github pages serves that. This work predates OCaml 5 so beat1 was the switch I had try-eio/dune at main · patricoferris/try-eio · GitHub.

Yes, not being able to interact with the DOM is definitely a downside to this approach. There are some other upsides though, like dynamic loading of cmis/cmas - you can do synchronous fetches of remote files that you can’t do if the toplevel is running in the main page. This can cut the file size down by a surprising amount. I’ve got some patches almost ready that’ll do this for the playground on

I did wonder whether it might be possible to have the compiler in the worker thread, and then inject the resulting javascript into the main page; this would allow for both the size fix and DOM manipulation.

This is a nicer way, still room for improvement though! Dynamic cmis by jonludlam · Pull Request #1 · tmattio/merlin-js · GitHub

1 Like

I’m curious how the current Try Eio evaluation works. Is it:

(1) we have an OCaml interpreter compiled to js, and it interprets the *.ml in the codemirror editor or

(2) the OCaml interpreter compiles the *.ml in the codemirror editor to js, then evaluates it ?

From @jonludlam 's comment above, it seems to imply (2), i.e. the ability to take the js, postmessage it to another iframe, and evaluate there. However, my current (possibly incorrect) mental model is (1), where since it’s an interpreter, there isn’t generated js code to ship – unless we move the interpreter itself.

Sorry, I wasn’t precise enough. The way the toplevel works is that there’s this magic external function reify_bytecode that takes bytecode and returns a function that can be evaluated. The way the jsoo toplevel works is that it replaces that magic function with a javascript function that calls into js_of_ocaml to turn the bytecode into javascript, then injects it into the page (somehow?) and again returns a function that can be evaluated. We’d ship the bytecode back from the compiler worker thread then call that function in the main page.


I wonder if there is an example showing the complier running in the browser. What I mean is that an example where multiple .ml files (thus modules) in the virtual file system are compiled (by js_of_ocaml compiled OCaml compiler) and

  1. the resulting JavaScript (assuming we define an entry file, link everything together, and use js_of_ocaml to transpile the bytecode to JavaScript) is loaded backed to the webpage and executed
  2. allow merlin to type check module A that depends on module B while using signature information contained in the compiled b.cmi file.

Not exactly what you are asking for, but learn-ocaml does that kind of stuff, taking user-supplied ml code, applying some custom validations to its AST, then compiling and running it against a pre-defined solution. This and its sibling try-ocaml have had evaluation in a worker for a long time too — you can’t really ask students to reload the page after an accidental infinite recursion.

They lack the merlin integration though :slight_smile:


@patricoferris : I hope this does not come off as entitled / asking someone to do work for free. With the Try EIO example you have shared, can you provide a minimal example of *.ml code for doing self.postMessage ?

  1. I know that the “OCaml interpreter” is being evaluated in a webworker.

  2. I know that in regular JS, a webworker can send a message to parent via self.postMessage

  3. I’m not familiar with the OCaml FFI; especially not in the case of jsoo.

  4. I’m wondering if you could show minimal ocaml code (running in the jsoo / repl) which does the equiv of self.postMessage(…) [from webworker to parent]


The XY problem here is I’m planning on having the parent register a onmessage handler, then have the webworker (running jsso / ocaml repl) send it msgs via postMessage.