I'm fascinated by WebAssembly and love that it exists but if anyone tells you they need to use WebAssembly to make the UI snappy I'd advise you interrogate that assertion thoroughly. I don't want to speak to this example too deeply because I don't know it (I see they're doing all sorts of stuff with audio so maybe they do need WebAssembly) but modern JavaScript VMs are very, very fast. 99% of webapps are absolutely f…
The frontend does all the rendering for the editor, which we want to stay within the frame budget. That's why we offload all data synchronization work (applying CRDT deltas, encrypting/decrypting data to/from websockets, IndexedDB caching, search, parsing JSON and so on) to the "backend" thread.
I think for apps like this, splitting the UI and data part up (kind of like a frontend and a backend in a classic client/server web app) is very useful to prevent blocking the main thread. In our case this "backend" is actually a SharedWorker, which has the added benefit that it's very easy to keep all state in sync with multiple open tabs/windows, and we just multiplex all incoming websocket events to all connected "frontends".
I agree passing messages is a bit clunky, but we’ve taken a similar approach to comlink so we can simply "await" a function call on the backend from the frontend. Besides setting that up once (or just using something like comlink), it's not much work. Okay except I found debugging on Chrome a bit clunky, as I think Firefox allows you to see all SharedWorker console output from within the main thread console for example (with Chrome you can open the inspector for shared workers separely). Plus we also have all kinds of other neat features with modern browsers these days, like the SharedWorker, and zero-copy communication using Transferable objects.