Hello,
A few months ago I tried to upgrade workbox from V2 to V3 beta and got some strange errors, so I decided to wait and try now with V3.20 and all those errors are not there anymore so congrats.
Can I request some help with the last bit, as I am having some problems getting it to work correctly, I will try to explain what I am trying to do:
Ok my old V2 Code was this:
workboxSW.router.registerRoute(
'/(.*)',
({event}) => {
return workboxSW.strategies.staleWhileRevalidate().handle({event}).catch((error) => {
// request.mode = navigate isn't supported in all browsers
// so include a check for Accept: text/html header
if (event.request.mode === 'navigate' || event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html')) {
// This assumes that you have /offline.html cached already, perhaps
// via your precache() call.
return caches.match('/offline-page');
}
// Generate Error
return error;
});
}
);
The V3 Code I tried this:
workbox.routing.registerRoute(
'/(.*)',
({event}) => {
return workbox.strategies.staleWhileRevalidate().handle({event}).catch((error) => {
// request.mode = navigate isn't supported in all browsers
// so include a check for Accept: text/html header
if (event.request.mode === 'navigate' || event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html')) {
// This assumes that you have /offline.html cached already, perhaps
// via your precache() call.
return caches.match('/offline-page');
}
// Generate Error
return error;
});
}
);
The above code didn't work on testing and did not scrape the webpages and when the internet turned off didn't work for any fallback.
Reading through the past issues as I know this topic comes up again and again, I found this code:
var networkFirstHandler = workbox.strategies.networkFirst({
cacheName: 'default',
plugins: [
new workbox.cacheableResponse.Plugin({
statuses: [200]
})
]
});
const matcher = ({event}) => event.request.mode === 'navigate';
const handler = (args) => networkFirstHandler.handle(args).then((response) => (!response) ? caches.match('/offline-page') : response);
workbox.routing.registerRoute(matcher, handler);
When testing this, it does scrape all the web pages, however on testing when the internet does turn off the offline webpage does not work. Also, I'm not sure how to modify it to make only the main webpages get cached and not the blog section.
It is worth noting before someone asks lol. Yes, I am precaching before doing this and using the following code:
workbox.precaching.precacheAndRoute([
'/', '/amp/home', '/offline-page', '/amp/offline-page'
], {
ignoreUrlParametersMatching: [/^utm_/],
directoryIndex: '/',
cleanUrls: false,
});
I did notice V3 has a whitelist and blacklist now, but I think that would not help my solution?
I have read and tried to find a solution or example in the documentation and there seems to be no official example of an offline fallback example. So I would like to request one be added to the docs. Also if possible could we get an official code example for an offline fallback, I'm sure many people have tried to code hacks for this issue - which may not be the best solution.
So when in doubt ask the experts and this is why I have written this issue.
p.s. Off topic, I am really interested in learning Streams API and read Jack's blog two years ago found here: https://jakearchibald.com/2016/streams-ftw/
Is it possible to add some more info as I want to learn more about this API, I feel it really can take service worker and other network/caching things to the next level. Google IO 2019 I feel we gonna hear about this API again and again.
I'm addressing your off-topic portion first 馃槃
p.s. Off topic, I am really interested in learning Streams API and read Jack's blog two years ago found here: https://jakearchibald.com/2016/streams-ftw/
Is it possible to add some more info as I want to learn more about this API, I feel it really can take service worker and other network/caching things to the next level. Google IO 2019 I feel we gonna hear about this API again and again.
I spoke about this at this year's I/O, with Workbox added to the mix; you can read and watch at https://developers.google.com/web/updates/2018/05/beyond-spa if you want to learn more.
We have a general recipe for "fallback responses" at https://developers.google.com/web/tools/workbox/guides/advanced-recipes#provide_a_fallback_response_to_a_route
The specifics of when to fall back, and what content to use as an alternative, often depends on the specifics of a web app's site structure and freshness guarantees. Based on the detailed requirements you've outlined for your use case, I'd suggest the following:
var staleWhileRevalidate = workbox.strategies.staleWhileRevalidate({
cacheName: 'html-pages'
});
const customHandler = async (args) => {
try {
const response = await staleWhileRevalidate.handle(args);
return reponse || caches.match(OFFLINE_URL);
} catch (error) {
return caches.match(OFFLINE_URL);
}
};
const navigationRoute = new workbox.routing.NavigationRoute(customHandler, {
// Configure with RegExps as appropriate.
whitelist: [],
blacklist: [],
});
workbox.routing.registerRoute(navigationRoute);
Let us know if that works for you.
@jeffposnick Thank you for your code, I am having some problems trying to add: event.request.mode === 'navigate' into your code. Also when testing it seems like the webpage that gets landed on shows the Offline Fallback even though it is there with a 200 Status.
I know the below code is wrong but shows you what I am trying to do:
const OFFLINE_URL = '/offline-page';
var mainPages = workbox.strategies.staleWhileRevalidate({
cacheName: 'main-pages'
});
const matcher = ({event}) => event.request.mode === 'navigate';
const customHandler = async (args) => {
try {
const response = await mainPages.handle(args);
return reponse || caches.match(OFFLINE_URL);
} catch (error) {
return caches.match(OFFLINE_URL);
}
};
const handler = new workbox.routing.NavigationRoute(customHandler, {
// Configure with RegExps as appropriate.
whitelist: [],
blacklist: [
new RegExp('/blog/(.*)'),
],
});
workbox.routing.registerRoute(matcher, handler);
Would be most grateful for some extra help on this matter. Also thank you for the video at Google I/O. I am learning so much from the Google Chrome Dev Team and have added many ideas on the videos into some production websites.
Hello, @ayumihamsaki
I just made a few changes on the code that @jeffposnick post before and now it's working for me.
var networkFirst = workbox.strategies.networkFirst({
cacheName: 'outside-pages'
});
const customHandler = async (args) => {
try {
const response = await networkFirst.handle(args);
return response || await caches.match('./fallback.json');
} catch (error) {
return await caches.match('./fallback.json');
}
};
workbox.routing.registerRoute(
/https:\/\/newsapi.org\/(.*)/,
customHandler
);
Tell me if it's working for you too :)
And about your code, the following line
return reponse || caches.match(OFFLINE_URL);
should be
return response || caches.match(OFFLINE_URL);
I think that's why it shows the Offline Fallback even when it shouldn't.
@jeffposnick @cauebasantos Thanks both for your inputs!
Gonna close this issue as I have fixed the issue, the problem I was finding was trying to use the NavigationRoute to create a blacklist and it's much better just to use registerRoute and do an inverse regex.
Most helpful comment
Hello, @ayumihamsaki
I just made a few changes on the code that @jeffposnick post before and now it's working for me.
Tell me if it's working for you too :)