I’m using js_of_ocaml (4.0.0) to compile OCaml to JS and using the brr library (0.0.3) to interact with the browser, but I ran into some interesting behavior.
(For reference, here is the original GitHub issue about this.)
Problems with alert
Here is some code for setting up the alert
function that is more or less the same as the one from the brr docs:
(* This works! *)
let alert msg =
let alert = Jv.get Jv.global "alert" in
ignore @@ Jv.apply alert Jv.[| of_string msg |]
You can use this function with no problems in both dev and release mode.
Switching from get
to find
breaks things
However, if you switch from get
to find
(which returns an option rather than raising), you get problems:
(* Works in dev mode, not in release mode *)
let alert msg =
match Jv.find Jv.global "alert" with
| None -> prerr_endline "no alert"
| Some alert -> ignore @@ Jv.apply alert Jv.[| of_string msg |]
When building with dune in dev mode, the above function works fine, however, when building in release mode, you get an Illegal invocation
error when trying to use the function.
Strangely, if you put a print call in there, it works fine again, even in release mode.
(* Works in both dev and release mode *)
let alert msg =
match Jv.find Jv.global "alert" with
| None -> prerr_endline "no alert"
| Some alert ->
(* If you add print here, it works again.... *)
prerr_endline "yay!";
ignore @@ Jv.apply alert Jv.[| of_string msg |]
Switching to call
from apply
works again
In javascript, you can call alert
on window
in the browser and indeed, this OCaml version works fine in both dev and release modes.
(* Works in both dev and release mode *)
let alert msg =
match Jv.find Jv.global "window" with
| None -> prerr_endline "no window"
| Some window -> ignore @@ Jv.call window "alert" Jv.[| of_string msg |]
Brr function reference
For reference, here is how the functions from the above examples are defined in the brr
library. (Taken from here.)
let global = pure_js_expr "globalThis"
external pure_js_expr : string -> 'a = "caml_pure_js_expr"
external get : t -> prop -> t = "caml_js_get"
let find o p = let v = get o p in if is_none v then None else Some v
external call : t -> string -> t array -> 'a = "caml_js_meth_call"
external apply : t -> t array -> 'a = "caml_js_fun_call"
Any thoughts on what may be going on here?