## Building a toplevel

A toplevel is an interactive OCaml environment (like `ocaml` or `utop`). Js_of_ocaml and wasm_of_ocaml can compile a toplevel to JavaScript or WebAssembly, allowing it to run in the browser. See the live demo.

### With js_of_ocaml

1. Initialize the toplevel in your OCaml code using `Js_of_ocaml_toplevel.JsooTop.initialize`

1. Build your bytecode with debug info and linkall:

       ocamlfind ocamlc -g -linkall -package js_of_ocaml-toplevel \
           -linkpkg toplevel.ml -o toplevel.byte

1. Compile to JavaScript with the `--toplevel` flag:

       js_of_ocaml --toplevel toplevel.byte -o toplevel.js

### With wasm_of_ocaml

1. Initialize the toplevel in your OCaml code using `Js_of_ocaml_toplevel.JsooTop.initialize`

1. Build your bytecode with debug info and linkall, linking `wasm_of_ocaml-compiler.dynlink` and `js_of_ocaml-toplevel.common`:

       ocamlfind ocamlc -g -linkall -package wasm_of_ocaml-compiler.dynlink \
           -package js_of_ocaml-toplevel.common -package compiler-libs.toplevel \
           -linkpkg toplevel.ml -o toplevel.byte

1. Compile to WebAssembly with the `--toplevel` flag:

       wasm_of_ocaml --toplevel toplevel.byte -o toplevel.js

### Limiting available modules

By default, all linked modules are available in the toplevel. To limit this, use `--export FILE` where `FILE` lists compilation unit names (one per line).

The `jsoo_listunits` tool generates this list from findlib libraries:

    jsoo_listunits -o units.txt stdlib str
    js_of_ocaml --toplevel --export units.txt toplevel.byte

The `--export` flag works the same way with wasm_of_ocaml.

## Using the Dynlink library

OCaml's `Dynlink` module lets you load bytecode files at runtime. This works in both js_of_ocaml and wasm_of_ocaml with some setup.

### With js_of_ocaml

1. Link `js_of_ocaml-compiler.dynlink` in your program (initializes dynlink support)

1. Build your bytecode with debug info and linkall:

       ocamlfind ocamlc -g -linkall -package dynlink \
           -package js_of_ocaml-compiler.dynlink -linkpkg main.ml -o main.byte

1. Compile to JavaScript with the `--dynlink` flag:

       js_of_ocaml --dynlink main.byte -o main.js

### With wasm_of_ocaml

1. Link `wasm_of_ocaml-compiler.dynlink` in your program (initializes dynlink support)

1. Build your bytecode with debug info and linkall:

       ocamlfind ocamlc -g -linkall -package dynlink \
           -package wasm_of_ocaml-compiler.dynlink -linkpkg main.ml -o main.byte

1. Compile to WebAssembly with the `--dynlink` flag:

       wasm_of_ocaml --dynlink main.byte -o main.js

Plugin `.cmo` files are compiled on the fly to WebAssembly and instantiated at runtime.

### Example

    (* main.ml *)
    let () = Dynlink.loadfile "./plugin.cmo"

With js_of_ocaml:

    # Compile main program
    ocamlfind ocamlc -g -linkall -package dynlink \
        -package js_of_ocaml-compiler.dynlink -linkpkg main.ml -o main.byte
    js_of_ocaml --dynlink main.byte -o main.js

    # Compile plugin
    ocamlfind ocamlc -c plugin.ml

    # Run
    node ./main.js

With wasm_of_ocaml:

    # Compile main program
    ocamlfind ocamlc -g -linkall -package dynlink \
        -package wasm_of_ocaml-compiler.dynlink -linkpkg main.ml -o main.byte
    wasm_of_ocaml --dynlink main.byte -o main.js

    # Compile plugin
    ocamlfind ocamlc -c plugin.ml

    # Run
    node ./main.js

## Loading precompiled files

By default, `Dynlink.loadfile` compiles `.cmo` and `.cma` files on the fly. You can also precompile plugins ahead of time for faster loading.

### With js_of_ocaml

Use `js_of_ocaml` to compile a `.cmo` or `.cma` file to JavaScript:

    js_of_ocaml plugin.cmo -o plugin.js
    js_of_ocaml plugin2.cma -o plugin2.js

Then load the resulting JavaScript file at runtime. In Node.js, use `require`:

    let require s =
      Js_of_ocaml.Js.Unsafe.fun_call
        (Js_of_ocaml.Js.Unsafe.js_expr "require")
        [| Js_of_ocaml.Js.Unsafe.inject (Js_of_ocaml.Js.string s) |]

    let () = require "./plugin.js"

In a browser, use a `<script>` tag:

    <script src="plugin.js"></script>

### With wasm_of_ocaml

Use `wasm_of_ocaml compile` to compile a `.cmo` to a `.wasmo` file, or a `.cma` to a `.wasma` file:

    wasm_of_ocaml compile plugin.cmo -o plugin.wasmo
    wasm_of_ocaml compile plugin2.cma -o plugin2.wasma

Then load the precompiled file using `Wasm_of_ocaml_compiler_dynlink.loadfile`:

    let () = Wasm_of_ocaml_compiler_dynlink.loadfile "./plugin.wasmo"

This skips the on-the-fly bytecode-to-Wasm compilation step, which can significantly reduce loading time for large plugins.

## See also

- Command-line options — The `--toplevel` and `--dynlink` flags
- Compilation modes — Whole program vs separate compilation
- `index` — Toplevel API