Warning: Reason support is experimental. We are looking for beta-tester and contributors.

Export OCaml code to JavaScript

This page explains how to make OCaml values (functions, objects, constants) accessible from JavaScript code.

Basic export with Js.export

Use Js.export to export a single named value:

open Js_of_ocaml

let () =
  Js.export "myMathLib"
    (object%js
       method add x y = x + y
       method abs x = abs x
       val zero = 0
     end)

From JavaScript:

myMathLib.add(3, 4);    // 7
myMathLib.abs(-5);      // 5
myMathLib.zero;         // 0

Exporting multiple values with Js.export_all

Use Js.export_all to export all properties of an object as top-level exports:

let () =
  Js.export_all
    (object%js
       method add x y = x + y
       method sub x y = x - y
       val version = Js.string "1.0.0"
     end)

From JavaScript:

add(3, 4);        // 7 (directly accessible)
sub(5, 2);        // 3
version;          // "1.0.0"

Exporting individual functions

You can export plain OCaml functions. They are automatically wrapped for JavaScript:

let greet name =
  "Hello, " ^ name ^ "!"

let factorial n =
  let rec aux acc = function
    | 0 -> acc
    | n -> aux (acc * n) (n - 1)
  in aux 1 n

let () =
  Js.export "greet" greet;
  Js.export "factorial" factorial

From JavaScript:

greet("World");    // "Hello, World!"
factorial(5);      // 120

Type considerations

Exported functions are automatically wrapped with Js.wrap_callback. However, you must convert OCaml values to their JavaScript equivalents (strings with Js.string, booleans with Js.bool, etc.). See type conversions for the full list.

Handling callbacks from JavaScript

When JavaScript passes a callback to your OCaml code, you receive a JavaScript function. Use Js.Unsafe.fun_call to invoke it:

let () =
  Js.export "utils"
    (object%js
       method forEach arr callback =
         let len = arr##.length in
         for i = 0 to len - 1 do
           let item = Js.array_get arr i in
           Js.Optdef.iter item (fun v ->
             ignore (Js.Unsafe.fun_call callback [| Js.Unsafe.inject v |]))
         done
     end)

From JavaScript:

utils.forEach([1, 2, 3], function(x) { console.log(x); });

Using with Node.js

Js.export and Js.export_all automatically use module.exports when running in Node.js:

(* math.ml *)
open Js_of_ocaml

let () =
  Js.export_all
    (object%js
       method add x y = x + y
       method mul x y = x * y
     end)

Build and use:

$ ocamlfind ocamlc -package js_of_ocaml,js_of_ocaml-ppx \
    -linkpkg math.ml -o math.byte
$ js_of_ocaml math.byte -o math.js
$ node
> var math = require("./math.js");
> math.add(2, 3)
5
> math.mul(4, 5)
20

Using in browsers

In browsers, exports are added to the global object (window):

<script src="math.js"></script>
<script>
  console.log(myMathLib.add(2, 3));
</script>

To avoid polluting the global namespace, you can export a single namespace object:

let () =
  Js.export "MyApp"
    (object%js
       val math = object%js
         method add x y = x + y
       end
       val utils = object%js
         method log msg = Console.console##log msg
       end
     end)