I register service worker this way:
/* eslint-disable no-console */
import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready() {
console.log('App is being served from cache by a service worker.');
},
registered() {
console.log('Service worker has been registered.');
},
cached() {
console.log('Content has been cached for offline use.');
},
updatefound() {
console.log('New content is downloading.');
},
updated() {
console.log('New content is available; please refresh.');
},
offline() {
console.log('No internet connection found. App is running in offline mode.');
},
error(error) {
console.error('Error during service worker registration:', error);
}
});
}
when I vue-cli-service build --mode production and then I deploy to the server, online I can correctly see the logs:
App is being served from cache by a service worker.
Service worker has been registered.
New content is downloading.
New content is available; please refresh.
It seems to download automatically the content, but from now, it still always show New content is available; please refresh (and in fact, the content is not refreshed).
It seems it won't refresh automatically? Only downloading? Why?
How can I refresh on updated()?
what I did in this situation was to resolve a promise that will reload the page for the user. This is nice because it waits and then does the page reload after the data has come in.
/* eslint-disable no-console */
import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready() {
console.log('App is being served from cache by a service worker.');
},
registered() {
console.log('Service worker has been registered.');
},
cached() {
console.log('Content has been cached for offline use.');
},
updatefound() {
console.log('New content is downloading.');
},
updated() {
console.log('New content is available; please refresh.');
Promise.resolve().then(() => { window.location.reload(true); });
},
offline() {
console.log('No internet connection found. App is running in offline mode.');
},
error(error) {
console.error('Error during service worker registration:', error);
}
});
}
you should use skipWaiting method of service worker object.
maybe this can help you:
updated(registration){
const waitingServiceWorker = registration.waiting;
if (waitingServiceWorker) {
waitingServiceWorker.addEventListener('statechange', event => {
if (event.target.state === 'activated') {
window.location.reload();
}
});
waitingServiceWorker.postMessage({ type: 'SKIP_WAITING' });
}
}
whether this code is working or not depends on your service-worker.js content.
but the idea is the same you should use skip waiting.
Related
Currently i am facing the "service worker navigation preload request was cancelled before 'preloadresponse' settled. if you intend to use 'preloadresponse', use waituntil() or respondwith() to wait for the promise to settle" and how can i load all my method sequence?
async mounted() {
this.startLoading();
try {
await this.initializeData();
} catch (error) {
// error
}
},
methods: {
initializeData()
{
axios.all([
this.get_list_class(),
this.get_list_library(),
this.get_list_teacher(),
this.GetOrderID(),
// this.getVideoContent();
this.getProduct(),
this.checkCustRegisterInfo(),
this.checkCustRegister(),
this.checkTicket(),
this.scrollToTop(),
]).then(axios.spread((...responses) => {})).catch(errors => {
console.log('Not load');
})
}
}
I'm building my first custom service-worker.js and I encountered this error.
I'm using Vue + PWA (workbox)
registerServiceWorker.js :
import { register } from "register-service-worker";
if (process.env.NODE_ENV === "production") {
console.log("service worker won't be registerd for now");
register(`${process.env.BASE_URL}service-worker.js`, {
ready() {
console.log("App is being served from cache by a service worker.");
},
registered() {
console.log("Service worker has been registered.");
},
cached() {
console.log("Content has been cached for offline use.");
},
updatefound() {
console.log("New content is downloading.");
},
updated() {
console.log("New content is available; please refresh.");
},
offline() {
console.log(
"No internet connection found. App is running in offline mode."
);
},
error(error) {
console.error("Error during service worker registration:", error);
}
});
}
service-worker.js :
console.log("Hello from service-worker.js");
In order to get rid of this error I just changed the Content Type of the service-worker.js file (using Microsoft Azure Storage Explorer -> right click -> properties -> ContentType)
PS: let me know if you know how to automate this.
i used to write pwa via vanilla javascript like this
importScripts('/src/js/idb.js');
importScripts('/src/js/utility.js');
const CACHE_STATIC_NAME = 'static-v4';
const CACHE_DYNAMIC_NAME = 'dynamic-v2';
const STATIC_FILES = [
'/',
'/index.html',
'/offline.html',
'/src/js/app.js',
'/src/js/feed.js',
'/src/js/promise.js',
'/src/js/fetch.js',
'/src/js/idb.js',
'/src/js/material.min.js',
'/src/css/app.css',
'/src/css/feed.css',
'/src/images/main-image.jpg',
'https://fonts.googleapis.com/css?family=Roboto:400,700',
'https://fonts.googleapis.com/icon?family=Material+Icons',
'https://cdnjs.cloudflare.com/ajax/libs/material-design-lite/1.3.0/material.indigo-pink.min.css'
];
self.addEventListener('install', function(e) {
e.waitUntil(
caches.open(CACHE_STATIC_NAME)
.then(function(cache) {
console.log('[Service Worker] Installing Service Worker ...');
cache.addAll(STATIC_FILES);
})
);
});
self.addEventListener('activate', function(e) {
console.log('[Service Worker] Activating Service Worker ...');
// clear old cache
e.waitUntil(
caches.keys()
.then(function(cachedKeys) {
return Promise.all(cachedKeys.map(function(key) {
if(key !== CACHE_STATIC_NAME && key !== CACHE_DYNAMIC_NAME) {
return caches.delete(key);
}
}))
})
);
// Tell the active service worker to take control of the page immediately.
return self.clients.claim(); // to ensure that activating is correctly done
});
//After install, fetch event is triggered for every page request
self.addEventListener('fetch', function(event) {
let url = 'https://pwa-training-4a918.firebaseio.com/posts.json';
if(event.request.url === url) {
event.respondWith(
fetch(event.request).then(res => {
let clonedRes = res.clone();
// in order to clear ol data if new data is different from the original one
clearAllData('posts')
.then(() => {
return clonedRes.json()
})
.then(data => {
for(let key in data) {
writeData('posts', data[key])
}
});
return res;
})
);
// USE Cache only Strategy if the request is in the static Files
} else if(STATIC_FILES.includes(event.request.url)) {
event.respondWith(
caches.match(event.request)
);
} else {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request).then(response => {
return caches.open(CACHE_DYNAMIC_NAME).then(cache => {
cache.put(event.request, response.clone());
return response;
})
})
})
.catch(err => {
return caches.open(CACHE_STATIC_NAME).then(cache => {
// i need to show offline page only if the failure is in the help Page
// because it does not make any sence if i show this page in case of the failure in files like css
if(event.request.headers.get('accept').includes('text/html')) {
return cache.match('/offline.html');
}
})
})
);
}
});
but when I'm trying to write my own in vuejs app I installed pwa via vue add pwa it created for me a file called registerServiceWorker.js that I don't understand because I'm not used to use it
This file contains the following
/* eslint-disable no-console */
import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready () {
console.log(
'App is being served from cache by a service worker.\n' +
)
},
registered () {
console.log('Service worker has been registered.')
},
cached () {
console.log('Content has been cached for offline use.')
},
updatefound () {
console.log('New content is downloading.')
},
updated () {
console.log('New content is available; please refresh.')
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error (error) {
console.error('Error during service worker registration:', error)
}
})
}
I don't know how to write my own pwa code here or where I can do that?
Also I don't know if it will work on localhost or not because from what I'm noticing it works in Production
So My Question is, How Can I Write PWA As I used to do with vanilla js in vue app? What are the steps should I do in order to accomplish my full custom PWA?
Can I Do That without using workbox?
if anyone can help me i'll be appreciated.
Thanks in advance.
I/(pretty sure most of us) won't likely throw to redo service worker from scratch in any project, Workbox is also recommended tools in Google Developers' page other than Vue CLI.
As the registerServiceWorker.js, that's boilerplate for your service worker cycle in your App, as the logs pretty straightforward in the flow of your app process
If you wanna to do from scratch still, i would suggest read https://developers.google.com/web/fundamentals/primers/service-workers/ to understand the fundamentals. I would recommend because service-worker pretty much "I hope you know what you doing with your app like what-when-to update/caching/do-when-offline/"
I'm using workbox and vuejs and I want to serve public/offline.html page when I have no internet connection.
I edit pwa section to vue.config.js for handle service-worker myself:
pwa: {
name: 'myapp',
workboxPluginMode: 'InjectManifest',
workboxOptions: {
swSrc: path.resolve(__dirname, 'src/pwa/service-worker.js')
}
},
I add this code for supporting serve offline page in service-worker.js:
console.log('in pwa');
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
// The precaching code provided by Workbox. You don't need to change this part.
self.__precacheManifest = [].concat(self.__precacheManifest || []);
// workbox.precaching.suppressWarnings()
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
self.addEventListener("fetch", function(event) {
event.respondWith(
fetch(event.request).catch(function() {
return caches.match(event.request).then(function(response) {
if (response) {
return response;
} else if (event.request.headers.get("accept").includes("text/html")) {
return caches.match(workbox.precaching.getCacheKeyForURL('/offline.html'));
}
});
})
);
});
So when I access to www.myapp.com/en or www.myapp.com/en/about I get the offline page.
But the problem is when I access to www.myapp.com - the workbox is serve the index.html file from the cache.
I can remove index.html from the cache, but when I online I DO WANT to serve the index from tehe cache.
So I am here in dilemma, how to do that?
My current vue application was created using vue-cli and it uses the register-service-worker package by default. When I successfully build the app in production and deploy it on my server(which also has SSL certificate enabled), the pwa is generated as expected by the help of provided service worker, but when I make some changes to the app and deploy the new dist after rebuilding to the server, the browser cache is not being cleared. In short the service-worker is not detecting any changes to the new build. The cache is cleared when I force reload the browser. But this solution is not convenient on mobile devices and it is not a good experience for any user to force reload the app time to time just to get updates.
I even tried clearing cache on updatefound hook provided by service worker but I think the event itself is not firing or else the updatefound event would have cleared the cache on it's own.
My current registerServiceWorker script looks like this:
/* eslint-disable no-console */
import { register } from 'register-service-worker';
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready() {
console.log(
'App is being served from cache by a service worker.\n'
);
},
registered() {
console.log('Service worker has been registered.');
},
cached() {
console.log('Content has been cached for offline use.');
},
updatefound() {
caches.keys().then((keys) => {
keys.forEach(async (key) => { await caches.delete(key); });
});
},
updated() {
console.log('New content is available; please refresh.');
},
offline() {
console.log('No internet connection found. App is running in offline mode.');
},
error(error) {
console.error('Error during service worker registration:', error);
},
});
}
What should be done to clear the cache after a rebuild and deployment?