OCaml console

The OCaml console WebExtension is like the browser JavaScript console but for OCaml. It provides an OCaml toplevel (REPL) to directly interact with the OCaml code that lives in the web page. Follow the install instructions.

The extension itself is totally dumb: it inputs OCaml phrases, evals them in your web page via an ocaml_poke global JavaScript object and writes the result to the OCaml console panel. The burden of providing the poke object and the associated toplevel machinery is on the web page, see these instructions.

Note. If you write to the Brr.Console from the OCaml console the output appears in the JavaScript console which has support to inspect the JavaScript values that underpin many of the OCaml values you manipulate with Brr. Hence it's a good idea to have both open as can be seen in the image below.

Extension installation

The extension is distributed with brr not via the browser specific app stores. It is installed in:

$(opam var etc)/brr/ocaml_console

and can be added to your browser from there.

Firefox

The easiest at the moment is to install the extension temporarily – this means however that it will vanish if you restart your browser.

  1. Navigate to about:debugging
  2. Click the button “This Firefox”
  3. Click the button “Load Temporary Add-on”
  4. Open the extension directory and select manifest.json. On macOS type shift-/ and paste the path to the extension directory; this allows you to access hidden folders (namely .opam) from the file selector.

These steps are taken from here.

Google Chrome

  1. Navigate to chrome://extensions.
  2. Enable “Developer mode” by clicking the toggle switch.
  3. Click on the “Load unpacked” button. Select the extension directory and click “Select”. On macOS type shift-/ and paste the path to the extension directory; this allows you to access hidden folders (namely .opam) from the file selector.

The Chrome extension tutorial may also help with a few images.

Microsoft Edge

Navigate to edge://extensions and follow the steps of Google Chrome.

Safari

The WebExtension API is not supported by Safari yet. But it seems support is on its way for Safari 14.

Web page instructions

You need to compile a JavaScript file that has the js_of_ocaml toplevel machinery in your page and exposes it via the poke object.

One way of doing this to link with the brr.ocaml_poke library and add this line:

let () = Brr_ocaml_poke.define ()

somewhere in your code. Alternatively linking against the brr.ocaml_poked with -linkall adds the above line to your program without having to modify it.

To be able to access all your program libraries and modules you need to compile the bytecode executable with -linkall and invoke js_of_ocaml with the --toplevel option, -I options to lookup to cmis of the modules you want to access and link with js_of_ocaml's support the toplevel and dynlinking. Here is a minimal example and instructions to poke it.

In practice adding the poke object will result in a insane blowup of your page size budget. This is totally unfit for production. Keep in mind that the whole bytecode OCaml compiler, the js_of_ocaml compiler, the toplevel machinery and the cmi files of the modules you want to access get embedded in the page.

Current limitations

It would be nice to be able to separately compile the poke object and needed machinery as its own ocaml_poke.js script and link it separately via the HTML file. However this is not possible at the moment as separate toplevel compilation is not supported – this means excessively long build times are needed for now to use the console on your programs.

The ocaml_poke object

The JavaScript object must be named ocaml_poke and live in the global object (globalThis) of the web page. It must expose the following object members and types (in OCaml record notation) :

{ version : int; (* current version is 0 *)
  ocaml_version : Jstr.t;
  jsoo_version : Jstr.t;
  init : unit -> unit;
  eval : Jstr.t -> Brr.Json.t;
  use : Jstr.t -> Brr.Json.t; }

init, eval and use should raise Jv.Error in case of problem (the right interface would be to return a promise but we cannot because of WebExtension API constraints). For now eval should always return a Jstr.t.

Note that this is the only thing the extension needs. If you don't want to use the Brr libraries to define the ocaml_poke object you can perfectly define the object your own way.

If you want to access an ocaml_poke object yourself use the Brr_ocaml_poke module.

Current limitations

This API is very crude we can do much better than that. A few things that would be nice:

The only hard constraint we have is that eval should return JSON since it's the only thing we can get back in the panel via chrome.devtools.inspectedWindow.eval / devtools.inspectedWindow.eval.