Comments (6)
You should exclude server pages from the sw interception and use NetworkFirst/NetworkOnly runtime cahcing handler, checking for offline in the page (or before allowing the user navigating to those ssr pages). My suggestion is to exclude SSR pages from sw interception (use workbox.navegateFallbackDenylist
), or at least exclude dynamic ones, you can use a custom runtime caching to include those SSR pages not being dynamic, for example a list (the content will vary but the route is static) (will not work on first navigation, that's, not being included in the cache in first server response, the cache needs to be created and cannot be done in the request).
Check the code in this PR, you can group pages in the same cache or just add a cache per route (not optimal): vite-pwa/nuxt#66
You can use this to exclude routes from sw interception, for example, excluding /list
route:
workbox.navigateFallbackDenylist = [/^\/list$/]
To add a custom runtime caching without any cache and following with the /list
route example (beware, you also need to include all the routes in navigateFallbackDenylist
, and when offline requesting the page will fail):
workbox.runtimeCaching = [{
urlPattern: ({ url, sameOrigin }) => sameOrigin && url.pathname.match(/^\/list$/),
handler: 'NetworkOnly',
options: {
/* check the options in the workbox-build docs*/
matchOptions: {
ignoreVary: true,
ignoreSearch: true
},
plugins: [{
/* this callback will be called when the fetch call fails */
handlerDidError: async () => Response.redirect('/error?offline', 302),
/* this callback will prevent caching the response */
cacheWillUpdate: async () => null
}]
}
}]
To add a custom runtime caching with cache and following with the /list
route example (beware, you also need to include all the routes in navigateFallbackDenylist
, and when offline requesting the page will fail if cache not created, should only happen in first request and then going offline and refreshing the page):
workbox.runtimeCaching = [{
urlPattern: ({ url, sameOrigin }) => sameOrigin && url.pathname.match(/^\/list$/),
handler: 'NetworkFirst',
options: {
cacheName: 'ssr-pages-cache',
/* cache only 200 responses */
cacheableResponse: {
statuses: [200]
},
/* check the options in the workbox-build docs*/
matchOptions: {
ignoreVary: true,
ignoreSearch: true
},
plugins: [{
/* this callback will be called when the fetch call fails */
handlerDidError: async () => Response.redirect('/error?offline', 302),
/* this callback will prevent caching the response when not 200 */
cacheWillUpdate: async ({ response }) => response.status === 200 ? response : null
}]
}
}]
OFC you can mix both strategies, adding multiple entries to the runtimeCaching array.
EDIT: in previous examples, update the error redirection to an existing error page or custom error page, if it is only in client side only it would be better, I don't remember if kit will create the error.html page (if so the html page should be in the sw precaching manifest)
from sveltekit.
If you're using injectManifest
strategy (custom sw), you've the equivalent via import { registerRoute } from 'workbox-routing'
, here an example, also with the corresponding denylist => navegateFallbackDenylist
: https://github.com/elk-zone/elk/blob/main/service-worker/sw.ts
from sveltekit.
Thank you so much for taking the time to reply @userquin, I really appreciate it.
To give some more context: I am using dynamic routing for managing client-side data stored in local IndexedDB that is periodically synced in the background when online, i.e. there is no actual server-side dependencies involved in rendering these routes prior to the service worker entering the picture (and the project includes nested slugs - so keeping the clean SvelteKit codebase would be nice). It is a pretty traditional SPA with SSR disabled entirely for the main app group, though of course not for e.g. the API.
Giving up offline access for these routes in my case would unfortunately defeat the main use case of the service worker, not to mention that the server would have no work to do for these routes - and they actually are already working perfectly fine offline! It is only when online and detection of a new version occurs that trouble starts brewing. The error page propagation works as expected when offline or when no new updates have been deployed.
I also believe that even with this approach it wouldn't solve the issue completely, as one would always be able to trigger this same behavior by going to any route that falls outside the deny list + runtime caching pattern (leading to the standard SvelteKit 404 error page and this infinite request loop). Maybe this could be addressed by inverting the solution and using an allow list instead, but in any case, it won't work for me sadly.
For now I resorted to runtime caching for version.json
for a short duration, which at least stops the flurry of server requests and lets the client-side navigation throttling kick in, though I suppose this will be highly browser dependent. It also should be quite an extreme edge case once live unless someone actively tries to reproduce it, as the service worker should get updated continuously and there should be few ways for a user to end up on an error page in the first place. Still, it would of course be preferable not to have to think about this.
I'll post an update if / when I've made any progress on understanding what causes this behavior.
from sveltekit.
Actually the example @userquin posted made me aware of some workbox options I hadn't considered before, which made me want to experiment with a more robust extension of the version.json
caching trick.
I used the following:
workbox: {
runtimeCaching: [
{
urlPattern: ({ url }) => {
return url.pathname === '/_app/version.json'
},
handler: 'CacheFirst' as const,
options: {
cacheName: 'version-cache',
cacheableResponse: {
statuses: [200],
},
expiration: {
maxAgeSeconds: 30,
},
plugins: [
{
cachedResponseWillBeUsed: async () =>
Response.redirect('/', 302),
},
],
},
},
],
}
...and expected this to make the service worker "detect" the request loop by accessing the cached response and exit the loop by redirecting to root, which should then at least update as normal. To my surprise, this didn't only fix the loop, but it did so without even losing the state of navigation.
The version.json
is fetched, then the cached one is accessed, the service worker is updated and the error page is displayed correctly (it even shows the one generated by the updated service worker if any updates were made). I guess the redirect intercepts the service worker and forces it to fallback to render the current page via the root entry point without actually forcing a navigation in the browser?
I triple-checked in case somehow I had reconfigured something else, but indeed the addition of the redirect on cached response is the difference between triggering the infinite loop and everything working across dynamic routes or any other invalid route in the app.
I have no explanation, but it works!
from sveltekit.
You can try building your kit app using development in the mode in your local, workbox modules should show a few traces in the console
from sveltekit.
Related Issues (20)
- Having an issue with ssr = false HOT 8
- Issues with SPA HOT 1
- Inject Register script or inline has no effect on output HTML. HOT 6
- [Info] Cloudflare Adapter Routes misses vite-pwa HOT 1
- Cannot find module 'virtual:pwa-info' or its corresponding type declarations HOT 26
- Importing 'virtual:pwa-register' causes bug on build HOT 3
- Make client Javascript work offline HOT 2
- Deprecated packages HOT 2
- Uncaught (in promise) non-precached-url: non-precached-url :: [{"url":"/"}] HOT 13
- InjectManifest `The 'swSrc' file can't be read. ENOENT: no such file or directory` error on Gitlab CI HOT 5
- Uncaught ReferenceError: process is not defined for injectManifest HOT 1
- Error: [InjectManifest] 'plugins' property is not expected to be here. HOT 1
- Support Node v20 HOT 1
- Uncaught SyntaxError: Unexpected token 'export' HOT 3
- `_app/version.json` should be included in sw precache manifest
- Please document that images that are outside of `/static` will NOT build in production HOT 2
- Workbox responses with cached data for network only requests HOT 20
- One of the glob patterns doesn't match any files HOT 6
- Please provide a minimal example
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sveltekit.