Painless Service-Workers with +page.sw.js
and hooks.sw.js
#6699
Replies: 4 comments 1 reply
-
Your suggestion is a great idea and would make things much nicer. Any updates on this? Did you find any good alternatives? |
Beta Was this translation helpful? Give feedback.
-
This sounds very good. Co-locating custom service worker logic with the affected routes will be a great benefit to development and diagnosis. |
Beta Was this translation helpful? Give feedback.
-
I ran into this problem when building a PWA with SvelteKit. I think something like this should be given serious consideration for SvelteKit 3. Perhaps it could also be expanded to include layouts. There should simply be a way to progressively provide an offline fallback for every dynamic part of the app. |
Beta Was this translation helpful? Give feedback.
-
This is a beautiful idea. Would love to see what the team thinks of this. |
Beta Was this translation helpful? Give feedback.
-
The Pain-Point
Writing service-workers sucks, especially if your app talks to a server often.
Here what you need to do if you want your app to work offline or with a poor connection:
In short: it's a pain and it does not scale.
How SvelteKit could help
Sveltekit could alleviate this pain by componentizing the service-worker. Instead of writing a single monolithic service-worker for your entire site, you instead define your service-worker logic on a per-page / per-endpoint level. This gets compiled into part of a monolithic service-worker.
Componentizing service-worker code to a single page is helpful in the following ways:
+page.sw.js
andhook.sw.js
are my attempt at creating a framework pattern that can reap these benefits.My
+page.sw.js
andhooks.sw.js
proposalAlongside
+page.svelte
, you would be able to define a+page.sw.js
. This would define the service-workers behavior for this page. It would mostly be used to mock+page.server.js
. Like+page.server.js
,+page.sw.js
would implementload
functions and form actions.When the page makes a request to a server side method (like
load
, or an action), the page's service-worker component gets a chance to intercept it. The worker is responsible for deciding how to proceed with the request from there. It can choose to respond directly (with cached data for example), or to pass the request on to a+page.server.js
, or really, it could implement any pattern the developer can dream of.It would probably be helpful to study an actual example to see how this behavior would be helpful for creating service-workers.
Let's say you have a page with a list of products. This list is loaded in the server-
load
function. When offline, we want to display a locally cached list of products instead of just failing outright.The
+page.sw.js
file would look something like this:Let's extend the example by adding a form to the page that creates a new product. We can intercept the form submission, and optimistically update the UI, even if no network is present.
It can't be assumed that service-workes are present. They are purely progressive enhancement. If a server-side
load
function, or form action that is not implemented by+page.sw.js
is called, it just goes along to the server.hooks.sw.js
is the service-worker equivalent ofhooks.server.js
. It should follow the interface ofhooks.server.js
closely. It would have ahandle
,handleFetch
and ahandleError
function.handle
Prepares a Request for the downstream+page.sw.js
handlers. This would be the opportunity to set event.locals, check authentication / authorisation, or to bypass the downstream handlers entirely.handleFetch
would be an opportunity to deal with external requests, that could not be targeted with*.sw.*
files.handleError
Deal with anyerror
events that might be thrown during*.sw.*
handler execution.How would this work with the existing service worker file?
Since this pattern only handles app-internal network interaction, and none of the other responsibilities of the service worker (like static-file caching or notifications), the regular
service-worker.js
file is still needed. We would need to come up with a way to inject the behaviour from the service-worker routes into the service-worker file.Here is one idea:
Everything
+page.sw.js
andhook.sw.js
can do can be handled inside the service-worker'sfetch
event. You could conceivably create a "magic import" that gives you a single function that implements all the behaviours the developers have defined in their*.sw.*
files, as well as the route-matching done by sveltekit. This function would take theFetchEvent
as an argument. It could then be used like so:Could this work for entire endpoints?
Probably. For any endpoint defined in a
+server.js
file, you could conceivably define a+sw.js
that deals with the same methods. The implementation would be analogous to+page.sw.js
Is this usecase important for SvelteKit?
If designed and implemented well, such a pattern for creating service-workers would make SvelteKit the most accessible framework for building PWAs and complex Webapps. At the moment, there really isn't any full-stack framework that deals with service-workers well.
This feature is not urgent. Most developers do not write PWAs, so it won't be considered a "missing" feature if it doesn't get implemented. There is a lot of stuff that is more urgent than this.
(The
*.sw.*
pattern doesn't interfere with anything. It could be added without breaking changes)Beta Was this translation helpful? Give feedback.
All reactions