I'd like to install a service worker to do some simple caching in my Seed app. For instance, I'd like to be able to fetch new data from the server but display cached data until the response arrives, then update the app to contain the newly arrived data. This would require sending messages to the Seed app to notify it of the new data.
Is this supported? I couldn't find any documentation about it. If it's not supported, what's the least-hacky way to make it work anyway?
I'd be completely OK with writing the service worker's code myself in Javascript and linking to it in the HTML, it's the communication with the Seed app that I'm not sure about.
Apologies if I've missed something obvious, I'm not super well-informed on web development.
simple caching in my Seed app
Why you need Service Workers for it? I don't have much experience with service workers because it would be overkill for all my apps, so I'm just curious. It's also the reason why we don't have an example or official Seed Rust wrapper for Service Workers yet.
However if I would need to integrate Service Workers, then I would use the similar process that we used while we were writing browser API wrappers for Fetch, LocalStorage, WebSockets, etc.
I would read MDN docs for Service Workers and JS API interface to know exceptions, bugs, compatibility issues, which APIs are experimental and deprecated, etc. E.g. on the first glance I see that SWs don't work in Firefox's private mode so I assume I will need to handle failed worker creation properly, not with just .expect.
I would study ServiceWorker API in web_sys. web_sys is basically Rust-typed browser API (short official info). However because of Web API inconsistency and JS + inheritance, web_sys links to MDN docs are sometimes dead and some Rust types are a bit different or created from scratch. For instance, go to post_message description and click on the link MDN Documentation => boom! 404. post_message (aka postMessage in JS world) doesn't belong to ServiceWorker directly, but to Worker.
Ok, now we know the most of footguns. Let's try it. First, we need to add necessary web_sys features - basically all web_sys items need at least one and it's written in the item's description - e.g. post_message requires feature ServiceWorker. An example how to add features to the Seed app.
There is a "weird" type in web_sys methods - JsValue - see e.g. post_message. It implements some Froms and as_* methods for simple Rust types but you'll often have to call helpers like .dyn_into or .dyn_ref manually to cast Rust types to JsValue and vice versa (see wasm_bindgen::JsCast for more info and similar methods; there are also many examples in the Seed code). Keep in mind that those conversions and calls can be slow.
_"it's the communication with the Seed app that I'm not sure about"_ - yeah, this part can be a bit tricky. I recommend to look at the example update_from_js and see create_js_handler + set_onerror call to get intuition for it. There are many other examples in the Seed repo (all handlers, streams etc, use it.) The general idea is to get App instance somehow (from App::start or from orders.clone_app; App cloning is cheap), throw it into Rust closure, call something like app.update(my_msg) to invoke update function in your app and then transform that closure to JS closure and throw into JS world through a web_sys method that expects this callback.
There are also helpers for transforming Js Promise to Rust Future and vice versa.
I don't know if it's possible to write Service Workers in Rust, but if you'd rather write them in Typescript, you can use seed-quickstart-webpack.
It would be very nice to have an example with workers in the Seed repo (/example) - I would be very glad if we can add it once you have knowledge about integrating them from your app.
Don't hesitate to write about your progress or other questions (here, chat, forum..)
OT: @bheisler Thank you for criterion.rs. I'm just using it to bench my proxy server for a client and when I found out how to write custom measurements and fire multiple requests it has become very useful tool for me.
@bheisler I am using a ServiceWorker for caching the website files locally in this app:
https://gitlab.com/mkroehnert/weightrs.
I use a plain JS ServiceWorker file, since it is what I saw in all the examples and I did the registration of the ServiceWorker in JS, since I was lazy.
From what I know, the ServiceWorker code can not be baked into the Seed application itself.
It runs separately from the application and sits between your application and the network. Otherwise it would not be possible to intercept network calls and such of the application itself.
Looking at MDN ServiceWorker, the first paragraph reads:
A service worker is an event-driven worker registered against an origin and a path. It takes the form of a JavaScript file that can control the web-page/site that it is associated with, intercepting and modifying navigation and resource requests, and caching resources in a very granular fashion to give you complete control over how your app behaves in certain situations (the most obvious one being when the network is not available).
This seems like the implementation of the ServiceWorker must be in JS.
I also checked the W3C draft, but could not find anything definite about the supported implementation language for ServiceWorker other than this part: https://w3c.github.io/ServiceWorker/#script-request.
It states, that ServiceWorker files are currently expected to be served with a JS MIME type and somewhere else, that an error is returned, if the MIME type is not JS.
Besides that, the registration of the ServiceWorker script should be doable inside the Seed application.
Entry point here is web_sys ServiceWorkerContainer::register() or register_with_options().
And as @MartinKavik mentioned already, interaction with the installed ServiceWorker should then probably work with web_sys ServiceWorkerRegistration or web_sys ServiceWorker.
Related PR: https://github.com/seed-rs/seed/pull/523
Service worker with notifications and caching demonstrated in the example https://github.com/seed-rs/seed/tree/master/examples/service_worker