Module Base.Main

Javascript Exceptions

type js_error

Type of a javascript exception.

val of_exception : exn -> js_error option

of_exception exn returns Some js_error if the exception exn is an exception raised by javascript code and None if exn is an exception raised by ocaml code.

val raise_js_error : js_error -> 'a

Raise the javascript exception js_error

val raise_js : string -> 'a

raise_js error Raise a javascript exception.

Logging

val log_string : string -> unit

log_string str Log the string str via console.log.

val log_value : Value.t -> unit

log_value v Log the javascript value v via console.log.

Node Module

The functions in this section allow the creation of node modules which can interact with the surrounding javascript code. The communication is based on message passing. The javascript side can send messages into the node module implemented in ocaml and the ocaml side can send messages to the javascript side.

In order to start the node module, initialisation data can be provided.

The implementation of the node module on the ocaml side is done by providing a function of the following type.

type ('state, 'msg) node_function = 'state -> (Value.t -> unit) -> 'msg -> unit

Type of the implementation function of the node module.

The implementation function has the form

let node (state: 'state) (callback: Value.t -> unit): 'msg -> unit =
    ... (* initialisation code *)
    ...
    fun msg ->
        ... (* receive a message from the javascript side *)
        ...

Having a node function and a state and a message decoder, a node module is generated by a call to the following function.

val node_module : 'state Decode.t -> 'msg Decode.t -> ('state, 'msg) node_function -> unit

node_module state_decode msg_decode node_function

An ocaml program my_app.ml with an ocaml statement of the form

let _ =
    node_module state_decode msg_decode node_function

compiles to my_app.js which can be loaded as a module in a nodejs script via

           var my_app = require('./my_app.js')

The javascript value my_app is a javascript object of the form

           {init: (initial_state, callback) => { ... }}

which can be used in the following way:

            function callback (msg) {
                ...     // actions on receiving a message from 'my_app'
            }
            var state =
                     ... // initial state which can be decoded
                         // by 'state_decode'

            var post_to_my_app = my_app.init(state, callback)

            post_to_my_app (msg)    // send message to 'my_app',
                                    // must be decodable via 'msg_decode'

Browser Application

The function in this section allow the creation of browser applications which can interact with the surrounding javascript code. The communication is base on message passing. The javascript side can send messages into the ocaml browser application and vice versa.

The implementation of a browser application with javascript interop on the ocaml side is done by providing a function of the following type.

type ('state, 'msg) browser_function = 'state -> string option -> (Value.t -> unit) -> 'msg -> unit

Type of the implementation function of the browser application with javascript interop.

The browser function has the form

let browser
    (state: 'state)                 (* initial state *)
    (element: string option)        (* optional element id *)
    (callback: Value.t -> unit)     (* send messages to javascript *)
    : 'msg -> unit
    =
    ... (* initialisation code *)
    ...
    fun msg ->
        ... (* receive a message from the javascript side *)
        ...
val browser_application : string -> 'state Decode.t -> 'msg Decode.t -> ('state, 'msg) browser_function -> unit

browser_application state_decode msg_decode browser_function

An ocaml program my_app.ml with an ocaml statement of the form

let _ =
    browser_application
        "my_app"            (* Unique name in the browser *)
        state_decode
        msg_decode
        browser_function

can be compiled to a javascript file my_app.js. This file my_app.js can be included within a html page in a script tag

            <script type="text/javascript" src="my_app.js"></script>

In the html file we need some javascript code to interact with the browser application.

 <script>
            var state = ...         // javascript value which can be decoded
                                    // by 'state_decode'

            var postMessage         // variable representing a function to
                                    // post messages to 'my_app'

            var callback (msg) {
                ...                 // actions on receiving messages from
                ...                 // 'my_app'
                ...
                postMessage (...)   // send a message to 'my_app'
            }
            </script>

At the end of the body the application my_app can be started by

            <script>
                postMessage = my_app.init (state, 'element_id', callback)
            </script>

Warning: The ocaml browser application shall not be initialized before the body and in particular the element is available. Therefore it is best to initialize the application at the end of the html body.

It is convenient to initialize the browser application with an element id below which the browser application should install itself in the dom tree. This can be used to avoid conflicting dom accesses between the javascript side and the ocaml browser application.

Global Environment

If your application written in ocaml wants to communicate with javascript code, then the following functions might be interesting.

With the function make_global it is possible to make a javascript value generated via ocaml available to the surrounding javascript code. In many cases you will make a function globally available to the javascript code. This function can receive initialization data and callback functions. With the callback functions you can post messages to the surrounding javascript code. Furthermore the globally accessible function might return a function which can be used by the surrounding javscript code to post messages to the ocaml application.

If you write a web worker, you have to make function with the name onmessage available to the global environment. This function has type Value.t -> Value.t and it usually returns Value.undefined. Via get_global you can find out, if a function named postMessage exists (it exists in the global environment of a webworker) and then you can use this function to send messages to the creator of the web worker.

val make_global : string -> Value.t -> unit

make_global name value Make the javascript value value accessible from javascript code via the global name name.

Caution:

If the global name name already exists, it will be overwritten. This has fatal consequences if you overwrite e.g. setTimeout or document or other other used global variables or global functions.

It is recommended to use some prefix like my_app_... in name in order to not pollute the global namespace.

val get_global : string -> Value.t option

get_global name Check, if name exists in the global enviroment and if yes, return the corresponding javascript value. Use Decode to check, if the global is a function, an object, a number etc.

val new_global : string -> Value.t array -> Value.t

new_global constructor args

Construct a new javascript object using the constructor constructor feeding it with the arguments args.

Precondition: The constructor must exist and it has to accept the arguments. If not, an exception is thrown.

val export : (string * Value.t) array -> unit

export [| name1, val1; name2, val2; ... |]

Export the javascript object consisting of the fields name1, name2, ... to the surrounding javascript code.

This function is used if you want to write a module to be used in a node application. In the javascript code you write

var my_app = require('./my_app.js')

and then the javascript variable my_app is an object containing all the exported fields.