diff --git a/CHANGES.md b/CHANGES.md index e7481e2973..62ad93751a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,9 @@ * Compiler: improved shape computation (#2198) * Add the --build-config and --apply-build-config flags (#2177) * Runtime/wasm: optimized some bigstring primitives (#2144) +* Runtime/wasm: dispatch `wasmoocaml:loaded` and `wasmoocaml:error` + `CustomEvent`s on `globalThis` so that surrounding JavaScript can wait + for the asynchronous Wasm instantiation to complete ## Bug fixes * Compiler: fix reference unboxing (#2210) diff --git a/compiler/lib/reserved.ml b/compiler/lib/reserved.ml index 1f5c87c834..baedb3f7cf 100644 --- a/compiler/lib/reserved.ml +++ b/compiler/lib/reserved.ml @@ -143,6 +143,7 @@ let provided = ; "btoa" ; "clearInterval" ; "console" + ; "CustomEvent" ; "global" (* only available in node *) ; "importScripts" (* only available in WebWorker *) ; "performance" (* Not available in node until v16+ *) diff --git a/runtime/wasm/runtime.js b/runtime/wasm/runtime.js index 3b53ea566f..024d5e07c2 100644 --- a/runtime/wasm/runtime.js +++ b/runtime/wasm/runtime.js @@ -776,34 +776,49 @@ } return { instance: { exports: Object.assign(imports.env, imports.OCaml) } }; } - const wasmModule = await instantiateFromDir(); - - var { - caml_callback, - caml_alloc_times, - caml_alloc_tm, - caml_alloc_stat, - caml_start_fiber, - caml_handle_uncaught_exception, - caml_buffer, - caml_extract_bytes, - _initialize, - } = wasmModule.instance.exports; - - var buffer = caml_buffer?.buffer; - var out_buffer = buffer && new Uint8Array(buffer, 0, buffer.length); - - start_fiber = make_promising(caml_start_fiber); - var _initialize = make_promising(_initialize); - if (globalThis.process?.on) { - globalThis.process.on("uncaughtException", (err, _origin) => - caml_handle_uncaught_exception(err), - ); - } else if (globalThis.addEventListener) { - globalThis.addEventListener( - "error", - (event) => event.error && caml_handle_uncaught_exception(event.error), - ); + function dispatchLifecycleEvent(name, detail) { + if ( + typeof globalThis.dispatchEvent === "function" && + typeof CustomEvent === "function" + ) { + globalThis.dispatchEvent(new CustomEvent(name, { detail })); + } + } + + try { + const wasmModule = await instantiateFromDir(); + + var { + caml_callback, + caml_alloc_times, + caml_alloc_tm, + caml_alloc_stat, + caml_start_fiber, + caml_handle_uncaught_exception, + caml_buffer, + caml_extract_bytes, + _initialize, + } = wasmModule.instance.exports; + + var buffer = caml_buffer?.buffer; + var out_buffer = buffer && new Uint8Array(buffer, 0, buffer.length); + + start_fiber = make_promising(caml_start_fiber); + var _initialize = make_promising(_initialize); + if (globalThis.process?.on) { + globalThis.process.on("uncaughtException", (err, _origin) => + caml_handle_uncaught_exception(err), + ); + } else if (globalThis.addEventListener) { + globalThis.addEventListener( + "error", + (event) => event.error && caml_handle_uncaught_exception(event.error), + ); + } + await _initialize(); + dispatchLifecycleEvent("wasmoocaml:loaded", { src }); + } catch (error) { + dispatchLifecycleEvent("wasmoocaml:error", { src, error }); + throw error; } - await _initialize(); };