Not at all. I’m not quite sure if the question relates to just interacting with web workers or interacting with web workers that are running the top-level like in try-eio. If it is the former, then I highly recommend the Brr library for working with browser APIs in jsoo. There is an example of communicating with a web worker too.
If the question is more related to how try-eio works then this is actually all abstracted away behind GitHub - patricoferris/js_top_worker at 9b2be884deb1fcbb3b869609a72fab7df6eb45d0 (sorry we’re working with lots of forks etc. hence the submodules in the repository). The idea being that js_top_worker provides a uniform interface to the “thing” running the top-level (whether it be in a web-worker or elsewhere). Right now it only supports a web worker so it might seem like overkill, but you could imagine instead having the top-level on the server and communicating via a web socket or something (you could then properly support parallelism with domains).
The library is a little hard to understand, but it is using rpclib to do all this abstraction. The README gives quite a good overview. But for example, you can see the function you are describing:
With callbacks being implemented with the postMessage as you mentioned:
And you receive messages via the onMessage event handler
Many thanks! I am starting checking learn-ocaml, but it seems that the project is massive enough where a quick glance didn’t land me on the relevant part of code.
If it’s not too much to ask, could you give a list of files I should be start reading to understand how the compilation is performed in that project?
I am afraid I am too busy at the moment to find the time to guide you through the code, which I would otherwise have been happy to. It’s indeed kind of a beast .
The part related to running the user user-code is in the grader subdirectory. Also this the upcoming version is able to mix that with pre-compiled bytecode.
If I am understanding correctly (correct me if not!), the client (in this case CodeMirror extension) is directly talking to merlin running in a web worker. An example of the data path is:
If I understand correctly, you can achieve something a bit like this by wrapping the jsoo FFI functions that are there, just not exposed in any meaningful way right now (like by the Js_of_ocaml.Js module or Brr’s Jv module). Reusing the code from Jv this will work in try-eio today:
type t
external repr : 'a -> t = "%identity"
external pure_js_expr : string -> 'a = "caml_pure_js_expr"
external apply : t -> t array -> 'a = "caml_js_fun_call"
external get : t -> string -> t = "caml_js_get"
external call : t -> string -> t array -> 'a = "caml_js_meth_call"
external to_int : t -> int = "%identity"
let global = pure_js_expr "globalThis"
module Console = struct
let console = get global "console"
let log i = ignore (call console "log" [| repr i |])
end
let add_one (x : int) =
let fn = pure_js_expr "((x) => x + 1)" in
apply fn [| repr x |] |> to_int
let () =
let i = 1 + 1 in
Console.log i;
let j = add_one i in
print_int j
A bit long, but I’m trying to show both defining JS functions and reusing browser APIs.
Not quite as slick as your variable name substitution but it works. If it was a feature you really wanted I would recommend pulling in Brr along with Eio and using the proper FFI there and as a bonus you will have all of Brr’s browser bindings to call directly in the editor too.
For anyone running into issues: note, the evaluation is happening in the context of the webworker, not the DOM, so we can’t do things like window.alert
Please note that this is still an early prototype and is hosted as a password protected preview deployment on Vercel.com. The link above should work since it contains an authentication token, but links generated using the “generate snippet link” button would ask for authentication in most cases.