Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[✨] add serviceWorker$ #53

Closed
serbyxp opened this issue May 20, 2024 · 13 comments
Closed

[✨] add serviceWorker$ #53

serbyxp opened this issue May 20, 2024 · 13 comments
Assignees
Labels
[STAGE-2] incomplete implementation Remove this label when implementation is complete [STAGE-2] not fully covered by tests yet Remove this label when tests are verified to cover the implementation [STAGE-2] unresolved discussions left Remove this label when all critical discussions are resolved on the issue [STAGE-3] docs changes not added yet Remove this label when the necessary documentation for the feature / change is added [STAGE-3] missing 2 reviews for RFC PRs Remove this label when at least 2 core team members reviewed and approved the RFC implementation

Comments

@serbyxp
Copy link

serbyxp commented May 20, 2024

Is your feature request related to a problem?

No

Describe the solution you'd like

A service-worker hook. For example serviceWorker$(…)

A hook that can be used anywhere in the project similar to worker$ or server$, but for the current service-worker ( qwikcity). The hook / wrapper function would act as a means for the optimizer to bundle the functions in it, to be ran on the service worker.

export const mySWFunc = serviceWorker$(()=> /* some function/s that will be bundled with the service worker. And executed on the service-worker when called, could be chunked and have their own QRL to be fetched later on when they are needed (same as normal $ but execute on the service-worker)
*/)

Describe alternatives you've considered

Currently adding functions to the service-worker.ts file.

Additional context

Currently there are no hooks to the optimizer / bundler. Adding a listener directly onto service-worker.ts does not take into account the current (built into setupServiceWorker() ) listener which could cause conflicts in the order of execution.

The service-worker does all the fetching for the chunks, acting as a proxy, if something is already cached in the service-worker , there is no entry point or “interception” point to modify the request between the main thread and the service-worker. Nor is there a mechanism to bundle code that should be executed on the service-worker… for example say a normal QRL $
The service-worker has a chunk for that, fetches it as needed, let’s say you want to manipulate it first on the service-worker, wrap it first…

  const domFunc = serviceWorker$(()=> {
  /* this runs on service-worker scope / thread,
     can do some “work” on the service-worker 
     before returning its QRL 
  */
    return $(()=> {
      /* this would run on the main thread
         Doesn’t have to be $ can just be an
         object with data or anything that
         can be serialized…
      */
    });
  });

  onClick$={domFunc}

There is currently an event$() in qwik that is similar to the above that is a QRL that returns a QRL with an implicit first arg which could be a similar way to set the serviceWorker$ … the key difference would be the “scope” of en vocation

Since it’s a QRL it’s not needed right of way…

First func$:
runs on service worker if it returns a QRL… it will need to be fetched before the main thread QRL is needed, so it can do its work before the main thread QRL is fetched and stay in an “awaiting” state to finish and returns the second (main thread) QRL

Second func$:
runs in main thread

I think this is a sort of callback but the callback is present on the service-worker so the second func$ can do some main thread work and return to the service worker

@serbyxp
Copy link
Author

serbyxp commented May 20, 2024

  • side note of the thought process
    how ever the server side handles QRL stuff needs to be “cloned” down to the service worker

so when the build happens you get a map with all the QRLs : chunks so anything in the serviceWorker$ would need to be parsed a second time to make a sub node with its own QRL : chunks

QRL/chunk1.js
Qrl/chunk2.js
QRL/swchunk1.js

swchunk1.js …
swchunk1/QRL/chunk3.js
swchunk1/QRL/chunk4.js

something along those lines, that it has its own map for what chunks it needs to handle..

I think by doing it in such a way would…
Create a ref or callback ref to the service-worker and more specifically the function that called it

This can lead to more exciting things like having the service worker act like a shared worker

ie executing more worker$ from the service-worker itself

serviceWorker$(worker$()=>…)

serviceWorker$(server$()=>…)

<input bind:value={z} />
<input bind:value={y} />
<button type=“submit” onClick$={[
  serviceWorker$(()=> {
    return y.value + z.value
  }),
  server$((x) => {
    return db.insert().values(x)
        return notification(x + “saved successfully“)
  }),
  // do a thing
]}>submit</button>

@PatrickJS PatrickJS self-assigned this May 21, 2024
@PatrickJS PatrickJS changed the title [✨]service worker hook [✨] add serviceWorker$ May 21, 2024
@JerryWu1234
Copy link

@PatrickJS
Maybe I can pick this.
looks a bit complicate,

@gioboa
Copy link
Member

gioboa commented May 22, 2024

This is an enhancement, the service worker story is changed during this month
Here is the new implementation
The output to solve this issue should be a cookbook example and not a new core API.
@JerryWu1234 feel free to play with this. Thanks

@gioboa
Copy link
Member

gioboa commented May 22, 2024

You can take inspiration from qwik-worker

@PatrickJS
Copy link
Member

PatrickJS commented May 22, 2024

yeah @JerryWu1234 feel free to experiment. I was thinking we can pass make a fetch request and in the service worker detect this and run the code in service-worker and return the results rather than returning the code. I was planning on experimenting with this in a week or so but if you want to try then I'll be happy to help 🙏

@PatrickJS
Copy link
Member

it would be better to have this which is similar to server$ but worker$ might be closer

const getDataFromServiceWorker = serviceWorker$((args) => {
  // do a thing
  return data
});

<button
  onClick$=[
    $(() => {

      const data = await getDataFromServiceWorker(args)
    })
  ]}
>
  Click
</button>

@seanperez-xyz
Copy link

seanperez-xyz commented May 24, 2024

You can take inspiration from qwik-worker

yeah the qwik worker$ last time i saw it did something similar... of event$
that is has a first arg and returns another function... ( if i remember correct)
...

but the worker$ is fine it can work universally ...
the only thing I remember * was that worker$ was using a ref off the q:container?? to "message"
but if we hone it down... that yes random worker$ ref whatever to spawn a new worker...
but IF qwik-city is the micro framework for routing THEN hook into that instead of q:container (or w.e it is) but thats not good enough... as worker$ should / could be worker$({...}:{type:'service-worker" | "worker" | "shared"; port?; , client?; etc..?; }

similar to worker$ it autos to q:container ?? as its ref, but for service-worker it refs off the qwik-city service-worker ? qwik-city[sw] : q:container

@seanperez-xyz
Copy link

seanperez-xyz commented May 24, 2024

its hard to explain, like if there is qwik city and there is a qwik city service-worker (throw it on there )... unless its specified to put it on a specific "port" or "client"or worker which behind the scenes would be an object of | worker , service-worker, shared-worker | whatever it is in "worker" lingo

so... its not changing anything to how it works now. its hooking into how it works now, and inject it as a ref based on the object its referencing

but all that has to happen behind the scenes ...

this is not helpful at all for normal I want to add this or that... but its helpful if I want to add a
"web API" like transitions or streaming API , storage API ( only one that works on main and worker threads is ? indexDB ? )... but its not so much yes I can add this to service-worker.ts but how can it be injected into the optimization process so that it can be a QRL in itself...
( QRL is handled by the service worker right... but a QRL that runs on the service worker) ... it can* fetch its own chunks/ bundles to run before the bundle needs to be fetched... its exactly what its doing now but a pre pre fetch that if you use the party-town method could be a pre-fetch to huge amounts of class methods that can serialize themselves in the background...( while streaming new qrl in..)

@seanperez-xyz
Copy link

seanperez-xyz commented May 24, 2024

like take a class for example... I cant serialize this class across $ boundries... and I dont need this class or module to run right now... but I do need it to run eventually... i can defer it , or like party-town I can just dump it to ?? some random fault ,,, and scoop it up later... but we already HAVE the service worker already its already doing things... but at the same time that its doing things it can do alllot more things... its no like the service worker is any different than any other thread...
it can pump out just as much work as any other thread... the key is not clogging up the main thread which is the UX ... but now think about the class barrier problem , its not that the class cant be broken across the $ barrier because I can make a type of string and call it type MyStringType= string;... and its going to complain ( bad example) but not really because all the web3 stuff complains because of a custom Hex type it cant serialize between that... for whatever reason... ( its a lint or w/e debacle) but they are both just strings

so the idea is okay forget about the hard part of figuring all that out ... lets just let the service worker to do it for us

class MyClass ... constructor...

its not going to serialize and there are 10000000s of libs like this that people spend 10000 of hours making but we cant use them in qwik ( we can the opt easy out no serialize method and useVisibleTask method ... but whats the point then...

but if we use the service worker it can hold alll that and it can hold it all in a stateful manner""

the page can change but the scope to the service worker doesn't
so it can run all that class madness back there in that thread.. while still being scoped to signals and all the serialized methods qwik uses, the difference is the SSR is not SSR but SWSR

@seanperez-xyz
Copy link

probably should copywrite that SWSR ... thats the extra$ for the sause$

@serbyxp
Copy link
Author

serbyxp commented May 24, 2024

You can take inspiration from qwik-worker

Like worker$ is great as I mentioned serviceWorker$ doesn’t need to exist it worker$ just gets an “upgrade” to reference the type of worker and give it a name to reference it in other files, or if the service-worker from qwik-city is in the scaffold that it gets imported to it

But right now as it is worker$ can be used, if for example you have a section of code that is no serialize | has the issue with a lot of class methods , if you get

const serializedOnWorkerData = worker$(() => // implement class methods | no serialize here
);

now you got serializedOnWorkerData to pass around, the problem with plain “workers” vs “service-workers” is there life cycle it closed with the tab page scope changes so it needs to be re executed, so holding state there while navigating might not be ideal. But on the service-worker as you navigate the scope doesn’t change so any objects that were created there can be referenced still?

  • just realized I’m logged in on a different GitHub account on my phone -Sean

— edit +
technically what can be done is you make a store, signal, and or context in the main thread where the data you get from the workers gets stored in like normal, so for example if the worker is calculating in the background and sends new data the on message or fetch listener can be ignored ? Since the data is going into the signal / store ? Which would trigger the re render of that component ?

@shairez
Copy link
Contributor

shairez commented Jun 3, 2024

Thanks everyone for the thoughtful discussion!
Our plan is to switch to the newer service worker implementation that can be updated with new graph data over time.

Until we'll be done with V2, we won't have time to allocate for a proper design for a feature like serviceWorker$
but we'll definitely get back to it after V2 is out (which is coming soon).

So writing this here just so you know we're not ignoring this, we're just pausing... and later we'll resume 😊

@gioboa
Copy link
Member

gioboa commented Oct 14, 2024

We moved this issue to qwik-evolution repo to create a RFC discussion for this.
Here is our Qwik RFC process thanks.

@github-project-automation github-project-automation bot moved this to In Progress (STAGE 2) in Qwik Evolution Oct 14, 2024
@gioboa gioboa transferred this issue from QwikDev/qwik Oct 14, 2024
@github-actions github-actions bot added [STAGE-2] incomplete implementation Remove this label when implementation is complete [STAGE-2] not fully covered by tests yet Remove this label when tests are verified to cover the implementation [STAGE-2] unresolved discussions left Remove this label when all critical discussions are resolved on the issue [STAGE-3] docs changes not added yet Remove this label when the necessary documentation for the feature / change is added [STAGE-3] missing 2 reviews for RFC PRs Remove this label when at least 2 core team members reviewed and approved the RFC implementation labels Oct 14, 2024
@QwikDev QwikDev locked and limited conversation to collaborators Oct 14, 2024
@gioboa gioboa converted this issue into discussion #112 Oct 14, 2024
@github-project-automation github-project-automation bot moved this from In Progress (STAGE 2) to Released as Stable (STAGE 5) in Qwik Evolution Oct 14, 2024
@shairez shairez removed this from Qwik Evolution Oct 15, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
[STAGE-2] incomplete implementation Remove this label when implementation is complete [STAGE-2] not fully covered by tests yet Remove this label when tests are verified to cover the implementation [STAGE-2] unresolved discussions left Remove this label when all critical discussions are resolved on the issue [STAGE-3] docs changes not added yet Remove this label when the necessary documentation for the feature / change is added [STAGE-3] missing 2 reviews for RFC PRs Remove this label when at least 2 core team members reviewed and approved the RFC implementation
Projects
None yet
Development

No branches or pull requests

6 participants