self should be Window or ServiceWorker.
I'm playing around with ServiceWorkers and self is limited to the Window class.
module App.SW
open Fable.Import.Browser
let self = self :?> ServiceWorker
self.addEventListener_install(fun installEvent ->
printfn "service worker installed, %A" installEvent
)
self.addEventListener_activate(fun activateEvent ->
printfn "service worker activated, %A" activateEvent
)
self.addEventListener_message(fun ev ->
printfn "%A" ev.data
)
addEventListener_install doesn't work without the cast.
let [<Global>] self: Window = jsNative
Is not always true.
I'd like to send a PR, how should we solve this? Erased Union Type that capture both Window and ServiceWorker?
I would probably do something like: self_window and self_service worker so the API is easy to use. If we do a DU then we need an active pattern, if we use U2<Window, ServiceWorker> there is an "unwrap" to do etc.
Good thinking, perhaps we could do the following:
let [<Obsolete("Use self_window")>][<Global>] self : Window = jsNative
let [<Global>] self_window: Window = jsNative
let [<Global>] self_web_worker : Worker = jsNative
let [<Global>] self_service_worker : ServiceWorker = jsNative
I never used self in JavaScript do you have any "simple" documentation or explanation on why/for what it is used ?
@nojaf Thank you :)
@whitetigle Didn't you work with service worker on a project ?
TBH I didn't know self was available in the bindings 😅 When I need it for web workers I usually just declare it.
The proposal looks good, although there may be a couple of points to consider:
- It's more verbose
selfis context sensitive, giving all three options may lead some users to believe they can use any one at any time.
AFAIK the current expert of service workers with Fable is @Nhowka ;) Maybe he also has some ideas on how to improve the API?
How do they decide what's the correct self in Typescript? I cannot find any example.
There is more returns for self:
Windowon normal usageDedicatedWorkerGlobalScopefor dedicated web workersSharedWorkerGlobalScopefor shared web workersServiceWorkerGlobalScopefor service workers
The only GlobalScope defined on the file is AudioWorkerGlobalScope that I'm not sure if self can return it directly. So as it is, even it being usable, it's not complete yet.
To be fair my opinion is more radical. Keep the current self : Window on Fable.Import.Browser and then have the specializations on their own packages, each one defining self to the expected type.
Ok, sounds good. So we would have something like Fable.Import.ServerWorker and this could be used independent of Fable.Import.Browser?
@MangelMaxime Yes but I did not migrate my service worker code to f# yet. So no problem with self 😉
I just registered the js code .
I'm too in favor for some specialized package.
@whitetigle Oh ok :)
@alfonsogarciacaro I believe this is how TypeScript does it.
@nojaf We could be less aggressive and just add a new module for each one, shadowing self when they are open. Not sure if the bindings take any space on the compiled bundle so having a real extra nuget package could be unnecessary.
I was planning on skipping the bindings entirely and doing a library exposing the service worker common uses via JavaScript files but if you can add the bindings even better.
Could you give an example how the shadowing would work? I don't know what happens when two module expose the same member. Last one wins?
Thanks for the links @nojaf
Could you give an example how the shadowing would work? I don't know what happens when two module expose the same member. Last one wins?
Yes, last module opened wins. That's why some Option methods are shadowed when opening Fable.Import.Browser :)
Maybe this is an opportunity to clean the Browser (and Core JS) bindings. They were originated from an early Typescript declaration and then it was edited manually over the time. It'd be nice to separate WebWorker and other bindings into their own packages. This could benefit the REPL as Fable.Import.Browser.dll is quite big to download (although I don't know how much space we'll be able to save if any).
I guess we could try running the latest Typescript DOM declarations with ts2fable, overwrite the current bindings and check the diff. But we need to be careful not to overwrite some of the manual changes (e.g. most event calls return a generic now in the bindings so you can just return unit instead of an object).
Is there any volunteer for this? 😸
The last time I tried to add just the ServiceWorkerGlobalScope and it was a horrible experience. As I added, the missing types would appear minutes later, modifying stuff were unbearably slow and I gave up. Probably it was because I don't have enough memory so the file was too massive for my machine to handle.
Now maybe the tooling is efficient enough for me to try again, but no promises.
I'll try to make some time for this as well.
Awesome, thank you @nojaf. Please let me know if you need any help.
Hmm ran dom.ts throught the latest version of ts2fable.
The file has become incomparable.

Maybe extracting Worker stuff from the Browser module is a safer approach.
Was the file generated with an earlier version of ts2fable? The output is impossible to merge now, but if it was maybe we can reuse that earier version again.
Hmm true, but many bugs would have been fixed since that release right? I'm suggesting the following:
- create a new file for workers based on ts2fable of lib/lib.webworker.d.ts
- remove any worker specific stuff from Fable.Import.Browser
Yeah, the file was generated with a very early version (also early version of the ts declaration) and there have been many manual tweaks since, so auto merging is going to be difficult :/
Your approach makes sense to me @nojaf. Removing should be easier. If it doesn't take too long it'd be also a good opportunity to remove old APIs like IE-only stuff.
As a side note, I need to check but an advantage of using newest ts2fable and dom.ts would be to add more comment documentation to the APIs. We don't have that many at the moment.
But we need to find a way to make it easier to see the diffing. I'll investigate, maybe writing a script to sort interfaces and members within the interface alphabetically.