From 9d3749f5f5677f68222f2f5514a4aedcd4f65b89 Mon Sep 17 00:00:00 2001 From: Jason Gross Date: Tue, 5 May 2026 12:23:28 -0700 Subject: [PATCH] Fix wasm worker: poll for synthesize and handle wasmoocaml events The wasm_of_ocaml launcher loads and instantiates the wasm module asynchronously, then runs the OCaml entry point that calls `Js.export "synthesize" ...`. The previous fixed 1s setTimeout in the worker raced against this and produced `ReferenceError: synthesize is not defined` on the deployed site (the wasm blob is now ~13.8 MB and routinely takes longer to load than 1s). Replace the timeout with a 50ms poll for `self.synthesize`, and also subscribe to the `wasmoocaml:loaded` / `wasmoocaml:error` events introduced in https://github.com/ocaml-wasm/wasm_of_ocaml/pull/143 so we install the handler immediately on success and surface load failures back to the page instead of looping forever. The loaded handler logs a note that the polling fallback can be removed once the deployed wasm_of_ocaml ships these events. --- fiat-html/wasm_fiat_crypto_worker.js | 58 +++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/fiat-html/wasm_fiat_crypto_worker.js b/fiat-html/wasm_fiat_crypto_worker.js index 9163c3d2f7..e6c4c2ffab 100644 --- a/fiat-html/wasm_fiat_crypto_worker.js +++ b/fiat-html/wasm_fiat_crypto_worker.js @@ -1,15 +1,61 @@ self.importScripts("wasm/fiat_crypto.js"); +// The wasm_of_ocaml launcher fetches and instantiates the .wasm +// asynchronously and only then runs the OCaml entry point that does +// `Js.export "synthesize" ...`, so `self.synthesize` is not defined +// when importScripts returns. Queue messages and poll until ready. +// Newer wasm_of_ocaml (https://github.com/ocaml-wasm/wasm_of_ocaml/pull/143) +// dispatches `wasmoocaml:loaded` / `wasmoocaml:error` on globalThis; we hook +// those when available and keep the polling fallback for older releases. let pending = []; +let ready = false; self.onmessage = function (e) { pending.push(e); }; -setTimeout(function () { - self.onmessage = function(e) { + +function installHandler() { + if (ready) return; + ready = true; + self.onmessage = function (e) { try { - const result = synthesize(e.data); - postMessage({result: result}); + const result = self.synthesize(e.data); + postMessage({ result: result }); } catch (err) { - postMessage({error: err}); + postMessage({ error: err }); } }; pending.forEach(e => { self.onmessage(e); }); pending = []; -}, 1000); +} + +function reportLoadError(err, src) { + if (ready) return; + ready = true; + const message = "wasm_fiat_crypto_worker: wasm load failed" + (src ? " (src=" + src + ")" : ""); + console.error(message, err); + self.onmessage = function () { + postMessage({ error: { name: "WasmLoadError", message: message, cause: err } }); + }; + pending.forEach(e => { self.onmessage(e); }); + pending = []; +} + +self.addEventListener("wasmoocaml:loaded", function (e) { + console.log( + "wasm_fiat_crypto_worker: received wasmoocaml:loaded; the installed " + + "wasm_of_ocaml is new enough that the polling fallback in this file " + + "can be removed (see https://github.com/ocaml-wasm/wasm_of_ocaml/pull/143).", + e && e.detail + ); + installHandler(); +}); +self.addEventListener("wasmoocaml:error", function (e) { + reportLoadError(e && e.detail && e.detail.error, e && e.detail && e.detail.src); +}); + +(function waitForReady() { + if (ready) return; + if (typeof self.synthesize === 'function') { + installHandler(); + } else { + console.warn("wasm_fiat_crypto_worker: self.synthesize not yet defined, retrying in 50ms"); + setTimeout(waitForReady, 50); + } +})();