Thanks for taking the time to look at my little demo, I know you are very busy with the Beta / Svelte migration.
I agree that your work on consolidating the UI into the shared Svelte code is more important. This is just something I personally want to play with.
If this is annoying feel free to tell me it is a hard no, and you do not want to discuss it further.
I am not totally married to this Wasm solution. I agree that that other solutions like JS addons that run in the frontend/ Web Workers have advantages and may be a better overall solution.
I brought up this topic because I recently had a look at Wasm Components, thought they were neat, and wanted to experiment to see if they could work well for Anki addons. (I’ve done a little more in the last few days, but thought it would be best to keep the demo I pushed to github simple).
I wasn’t trying to argue that UI interaction would be done exactly like that, just that it is possible to do UI interaction from Wasm.
I’m new to the Anki codebase and there is a lot to figure out. I have not yet dug into how the Python/QT WebView
↔ Svelte UI
is all hooked up.
I had got as far as the rslib
↔ Python
part so I just made something simple with what I understood.
I for UI hooks beyond just “I want a button in this menu” I envisioned the addon author would provide HTML+CSS+JS that Anki would inject into its UI in a dedicated IFrame / a dedicated WebView at the relevant point. i.e. We would give them specific extension points, not direct access the the main UI, so there would be less chance of conflicts with other addons/breakage on future UI updates.
We would then give them a JS API something like:
on_message_from_addon(callback: fn(message: JSON) -> ());
post_message_to_addon(message: JSON);
Then for the rslib
↔ frontend
side of things it would be something like:
poll_message_from_addon() -> (addon_id: GUID, message: JSON)
post_message_to_addon(addon_id: GUID, message: JSON)
The frontend code would then have a thread/coroutine calling the poll
method and dispatching the messages from rslib
in a loop. (N.B. no rslib
callback into Python).
There would still be a lot to figure out if we did go down this route.
e.g.:
- Do we let addons dynamically edit UI, or do they have to statically declare it in a manifest file?
- Do we provide convenience methods to addon UI to let them do common things directly from JS, or require all the business logic to be in the Wasm code?
Marshalling
I agree this may be a problem, but I’m not sure how much of one it would be.
It would depend greatly on how fast the Wasm marshalling is and what we are doing.
For your bulk note update example:
It could be horrible e.g.: if Wasm marshalling is very slow and we want a full copy of the objects on the frontend right now. We waste a lot of extra time marshalling back and forth between rslib
, wasm
and frontend
.
It could be better than it is currently e.g.: if Wasm marshalling is faster than protobuf and we do not need the objects in the frontend right now. We spend less time marshalling between rslib
and wasm
than we would have between rslib
and frontend
.
N.B. WIT allows you have resources
(handles) which could reduce the amount of copying.
If the before-add-note
part of my demo was refactored to use resources
(handles) instead of records
(structs) you only pass the deck-id
and a Note handle into Wasm memory on each call. There could then be no further copying (e.g. we ignore notes in that deck) or only limited copying (only the fields we access)
This is true, but JS / Web Worker based addons come with their own disadvantages as well.
It seems to me that JS addons would require you to do one of:
- Re-implement the entire addon infrastructure on each platform.
- Put a lot of non-UI addon logic into shared JS that each platform needs to run somehow.
- Throw away the existing desktop/ IOS/ android apps and replace them with a single cross-platform toolkit like Tauri.