Our platform is old angular (v4) and we use plain JavaScript file (sw.js) to register Service worker in index html page. I see install and activate are working fine. Just simple events [for testing]
self.addEventListener('install', function(event) {
event.waitUntil(self.skipWaiting()); // Activate worker immediately
});
self.addEventListener('activate', function(event) {
event.waitUntil(self.clients.claim()); // Become available to all pages
});
Then Angular component routes to our main page via router.navigate('pagename')
and browser even routes to that page, but service worker fetch event is not triggered..
self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
Any idea how to fix this issue? Thank you.
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});
Related
I have a PWA made with HTML, CSS and JS with Node.js, everytime I change the styles.css of the app, I have to upload it again, I.e. change the port. For example in localhost:3000 it would have the old styling, but if I upload it to localhost:3100, the styling changed to the new one, how can I make it so that cached css files will be deleted and uploaded with the new ones?
This is my service worker:
var CACHE_NAME = 'version-1'; // bump this version when you make changes.
// Put all your urls that you want to cache in this array
var urlsToCache = [
'index.html',
'assets/logo-192.png',
'images/airplane.png',
'images/backspace.png',
'images/calcToggle.png',
'images/diamond.png',
'images/favicon.png',
'images/hamburger.png',
'images/history.png',
'images/like.png',
'images/love.png',
'images/menu2.png',
'images/menu3.png',
'images/menu4.png',
'images/menu5.png',
'images/menu6.png',
'images/menu7.png',
'images/menu8.png',
'images/plane.png',
'images/science.png',
'images/settings.png',
'images/trash.png',
'styles.css'
];
// Install the service worker and open the cache and add files mentioned in array to cache
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
// keep fetching the requests from the user
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) return response;
return fetch(event.request);
})
);
});
self.addEventListener('activate', function(event) {
var cacheWhitelist = []; // add cache names which you do not want to delete
cacheWhitelist.push(CACHE_NAME);
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
if (!cacheWhitelist.includes(cacheName)) {
return caches.delete(cacheName);
}
})
);
})
);
});
If you are doing this for development just open your dev tools. Select the application tab, then the service worker panel.
Click the 'Bypass for Network' option.
I wrote an article on service worker dev best practices that might help:
https://love2dev.com/serviceworker/development-best-practices/
If you need to update in production that is different. I generally do a periodic HEAD request on the network asset (CSS file in your example). If the resource is newer than the cached version I update to the latest version as needed.
I have other techniques I use from time to time as well. It varies by application and the requirements, etc.
I transformed my React application into a PWA and it is working partially fine.
I followed this tutorial: https://medium.com/#toricpope/transform-a-react-app-into-a-progressive-web-app-pwa-dea336bd96e6
However this article only shows how to cache static data and I also need to store data stemming from the server, I could do this following the instruction of the first answer of this post: How can I cache data from API to Cache Storage in React PWA? and inserting the firebase adresses where the data is stored into the array urlsToCache, populated by the files that should be stored into the cache.
So far so good, however after the data be stored into the cache, the application stops fetching data from the server and loads the page only with data from the cache, even if the server is updated. This is what I need to fix.
In short, I need to fetch the data from the server, store it into the cache in order to use it when the application is offline and update the cache every time the server is reached.
I am trying to follow this guide, but without success: https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#serving-suggestions
This is my worker.js file:
var CACHE_NAME = 'pwa-task-manager';
var urlsToCache = [
'/',
'/completed',
'/index.html',
'/static/js/main.chunk.js',
'/static/js/0.chunk.js',
'/static/js/1.chunk.js',
'/static/js/bundle.js',
'/calculadora',
'https://calc-marmo.firebaseio.com/clientes.json',
'https://calc-marmo.firebaseio.com/adm.json',
];
// Install a service worker
self.addEventListener('install', event => {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
// Cache and return requests
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});
// Update a service worker
self.addEventListener('activate', event => {
var cacheWhitelist = ['pwa-task-manager'];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
Any help would be much appreciated.
This sound like you need a Network First strategy which is not mention in the cookbook. This strategy is similar to Network falling back to cache but additionally stores the response always in the cache.
Explanation: https://developers.google.com/web/tools/workbox/modules/workbox-strategies#network_first_network_falling_back_to_cache
Code sample (if you don't use workbox): https://gist.github.com/JMPerez/8ca8d5ffcc0cc45a8b4e1c279efd8a94
My single page web application, is written as PWA. It's a ASP.NET Web API application, which is hosted under IIS. My application uses a service worker, which precaches my application shell. Other content is written to indexedDB or updated in the service worker cache on-the-fly, as the user clicks through the application.
I have a problem with code changes. When I update code, and refresh my browser, I can see my changes directly in the javascript and html code. When I go offline, my application falls back on the code, which is in my service worker. This code is still old code. It seems not to be updated, when i reload my application. My service worker looks like this:
const urlsToCache = ['.'
, 'index.html'
, 'favicon.ico'
, 'service-worker.js'
// More sources are cached here
];
self.addEventListener('install', function (event) {
console.log('\'Install\' event triggered.');
event.waitUntil(
caches.open(CACHE).then(function (cache) {
console.log('Application shell and content has been cached.')
return cache.addAll(urlsToCache);
}).then(function (event) {
return self.skipWaiting();
})
);
});
self.addEventListener('activate', function (event) {
console.log('\'Activate\' event triggered.');
return self.clients.claim();
});
For registering the service worker, my code looks like this:
navigator.serviceWorker.register('./service-worker.js')
.then(function (registration) {
console.log('Registered: ', registration);
registration.update();
console.log('Updated: ', registration);
resolve(registration);
}).catch(function (error) {
console.log('Registration failed: ', error);
reject(error);
});
So when the service worker get registered, it also checks for updates. However, it only updates when the service worker code itself is changed. Not when code within my application shell is changed without changing the service worker code itself.
How can i make sure that the code in my service worker is reloaded when I change my application code and refresh my page?
I'm creating a PWA using React.
My Service Worker seems to be working fine except for the fetch event listener, which does not execute when a GET HTTP request fires within my React app using the fetch API to get data from an external API on the web.
Where should I be placing my fetch event listener?
Does it work for external requests or only for requests to files that are part of the app?
Please let me know if you notice any issues with my code below.
I'm using the boilerplate Service Worker file that comes when using create-react-app to start a new project.
Here is my code:
(The execution never gets into the window.addEventListener('fetch', ...) part)
function registerValidSW(swUrl) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
window.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
if (response) {
return response
}
return fetch(event.request).then(response => {
caches.open('fetch').then((cache) => {
cache.put(event.request, response.clone());
});
return response;
})
}
)
);
});
console.log('New content is available; please refresh.');
} else {
// static files caching
cacheStaticFiles();
// external api data caching
cacheApiData();
// At this point, everything has been precached
console.log('Content is now cached for offline use.');
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
So I ran into this issue. It turns out that CRA actually compiles that service worker into a different service-worker.js file in your build folder, and that gets registered. If you append your code to the end of that file it will work, but annoyingly you'd have to do that on every build.
I'm using this addin: https://www.npmjs.com/package/cra-append-sw to append it automatically instead.
At present it had this minor issue, which requires running it with a different option: https://github.com/tszarzynski/cra-append-sw/issues/18
Is it possible to show an offline cache of my website when the server is down?
All the examples I can find regarding offline pages has to do with the client being offline. What I need is to show the user a cached version of my site if the server can't be reached.
I've read about the Cache Manifest in HMTL 5 but it's getting removed and it causes to many problems.
What can be done without using any other loadbalancing servers and such?
I recently learned that with Fetch API and service workers its dead simple:
First, you register the Service worker:
if (!navigator.serviceWorker) return;
navigator.serviceWorker.register('/sw.js')
Then configure it to cache whats needed:
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(staticCacheName).then(function(cache) {
return cache.addAll([
'/',
'js/main.js',
'css/main.css',
'imgs/icon.png',
]);
})
);
});
And use Fetch API to get cached peaces if no response from the call:
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request);
})
);
});
if need to get cached version only if server is down, try something like:
self.addEventListener('fetch', function(event) {
event.respondWith(
return fetch(event.request).then(function(response) {
if (response.status !== 200) {
caches.match(event.request).then(function(response) {
return response;
}).catch(function(error) {
console.error('Fetching failed:', error);
throw error;
});
})
);
});
p.s. using Fetch API seems much nicer way than implementing old and nasty XMLHttpRequest.