Currently, I’m porting a desktop app to the web.
The app gui is written in egui, and compute-heavy tasks use threads both for improved user experience and for increased performance.
But: On the web threads cannot be used - because the API just does not exist.
A partial replacement is called webworkers.
In this short blog post, I adjust the eframe-template app to use webworkers.
You can find the example here.
This does not work.
Here is the error message on Firefox and Chrome.
Note that the Chrome error is much more helpful.
Also note, that log statement after the thread.spawn(…) is not reached.
Solution
The solution is to replace the thread on Wasm with a webworker.
For this we will use the crate gloo_worker:
We will need to adjust the index.html file as well as some rust code.
The Gloo worker
We add a new rust file, webworker.rs.
Then we implement gloo_worker::Worker, using rust-analyzer:
which we fill in with typed dummy data
Adjusting fn new(…)
Next we proceed with app.rs.
We start our webworker together with our app, so we adjust fn new(cc : ..).
If our webworker sends a response, we collect the latest and ask egui to repaint.
Do you see this funny javascript file? We come back to it later.
1
We adjust the TemplateApp accordingly, from
to
and stores the added data in the new function.
Finally, we work with the update method:
We check if there was a request, by adding the following code snippet:
Then, in the button of the egui template, we trigger our webworker
Thus, we exchange
with
Now, we finally can try it (and fail …)
Remark: If you reload the egui web app, you might need to unregister the service worker, check about:serviceworkers (Firefox).
The error messages, Chrome and Firefox:
Both errors point to the javascript file, dummy_worker.js, which we used in the spawn function.
Remark: Note that our app does no longer run on the desktop :-/
Adding a second binary
The missing javascript file will automatically be generated by trunk serve.
To this end we add a second binary to our crate2.
We create a new file, dummy_worker.rs:
Finally, we need to adjust index.html, to communicate this change to trunk:
we replace
with
Now it works :-)
Clicking on increment, sends messages:
Further questions
The logging statement from the WebWorker is not working. I’m unsure why.
The trait gloo_worker::Worker has an associated type “Message”. What does it do?
Can we start multiple web workers? A dynamic number?
I plan to test this next.
When is the create function of the gloo_worker actually called?
I’ve cheked that it is not called during the spawn function of our bridge.
I tried to debug it, setting a break point inside the create function of the WebWorker struct.
But clicking on the button in the GUI still works, even if paused in this breakpoint …
Footnotes
when is the spawn actually executed? -> see below ↩
Crate is wrong, I guess. Package seems to be the correct term. ↩