It looked that at times the new bundle files don’t pick up after a code update and I’d need to manually refresh the page in order to have the new Meteor bundle running. I think this requires more testing…
clients.claim() just triggers the event ''controllerchange". The following part of code that is part of the SW registration, prevents multiple reloads on the same session.
After failing for some time to load the new bundle and to pick up on the offline HTML when required, the idea came from here: https://github.com/VeliovGroup/Meteor-Files-Demos/blob/master/demo/public/sw.js
To be frank, I have not exactly fully understood the implications of calling clients.claim() multiple times but it looks that, at least for me, things are now working as desired. The ''controllerchange" event is actually only triggered on a first load (or refresh) of a page. I’d prefer to take control and ensure the availability of the bundle files from cache (or newer) at every load of the browser and not only on the activation of the service worker.
const doTabsRefresh = () => {
// Refresh all tabs after a service worker update takes place
console.log('how often I call refreshing?!!!') // check this line
let refreshing
navigator.serviceWorker.addEventListener('controllerchange', () => {
if (refreshing) { return }
refreshing = true
window.location.reload()
})
}
I am not sure what you mean. Anyway, this is an example of how to sniff on the traffic. You can listen particularly to anything that passes through the browser. I activated debugging on my test domain: https://www.activitree.com and when set with your debugger as per the documentation (mainly Preserve History ON) you can see everything that passes through.
If I don’t exclude those, the fetch API tries to get that URLs and the router seems to reply with “Page not found”. It might be my case in particular as I am redirecting to a 404 page when a page is invalid for my platform but just to make sure they are always available as files and not as routes, I exclude them. No need to cache them, I need them network first. They are only handled on event.request.mode === 'navigate' which means either a first enter in the page or a refresh of the page. This is not being called otherwise.
If the fetch doesn’t match any strategy (which basically means that it falls under the last if (), the response is returned so in principle everything else remains untouched and passed from the network.
By default, a page’s fetches won’t go through a service worker unless the page request itself went through a service worker. So you’ll need to refresh the page to see the effects of the service worker.
So technically, a clients.claim() within fetch does nothing because fetch only goes through a service worker that has control of the page. From the same page:
You can take control of uncontrolled clients by calling clients.claim() within your service worker once it’s activated.
I want from my Meteor PWA to load much faster.
For instance, right now Telegram loads instantly, WhatsApp takes up to 3 seconds, and any Meteor app takes between 6 to 8 seconds.
It’s the Meteor initialization code that takes long to start up.
I used @jkuester’s guide to officially make my Meteor + Vue app a PWA and get the installable Chome menu. A big thanks to @jkuester for the blog post:
Just a small tip for anyone using Galaxy like me, because Galaxy has a feature to force SSL, I didn’t need the extra force-ssl package in my project.
And Chrome’s Lighthouse audit did give me a nice list of small performance improvements for my apps load time that might have been hard to figure out without it, so I think that is a pretty nice bonus to going through this process too.
It really is simple and after doing this process, and doing A LOT of additional reading on PWAs now, I do think documentation is the best resource for getting most people to turn their app into an official PWA.
I also did some testing on iOS and the App created on my iPhone is pretty great and non-distiguishable from a native app. So I have to say I’m very impressed with the benefits that come to devs from just adding a couple files to your project.
All my static assets are now cached thanks to the Service Worker and that just saves future wasted load time, so it is really a benefit to any app.
I designed my app to be both a mobile & desktop app from the beginning, so I feel like I got a HUGE time saver in not needed to work on Cordova & Electron versions of my app.
@vikr00001 I did also find a super easy way to work with notifications too, maybe @jkuester could add this as an extra step to his guide. However, I guess these notifications are not specifically a detail of a PWA per Google’s Lighthouse audit, but most people would find this very useful.
This is all you need to run on the client to get permission from your users for Notifications:
Notification.requestPermission()
And to send a notificatoin, this is all it takes:
new Notification('Message Text', {
body: 'Message Sub-Text',
icon: '../../assets/images/logo.png'
})
Copy and paste those and run them in your Chrome console, I couldn’t believe notifications were so simple using the direct Web Notificatoins API
The good news is that every major modern browser on the desktops support these native browser notifications, very cool! And Android devices also have full notification support. iOS devices are the acception right now, but rumor has it that iOS 14 (coming in Sept 2020) will support this API and perhaps other PWA features where iOS is lagging, but that is just the current rumor. Some people are watching this very closely.
For me notifications are a “nice to have”, so this is a pretty good solution to bank on as the community seems certain Apple will be getting on board very soon, at which time we could see a major PWA revolution take place.
I found a really nice guide by @flaviocopes about this Notificatoin API, super handy! Also if you want to send notifications when a user has closed your app, you would need to also use the Push API which uses your Service Worker when your app is closed.
I really recommend reading these Guides by @flaviocopes as they are the best resources I’ve found on understanding the basics. After reading those, the MDN web docs are handy on these topics too.
@mullojo Bob, we do have separate Frontend and Backend Meteor apps (which currently both run on AWS). Now we do have the need for the Frontend app to become a desktop app. I’m wondering if PWA or Electron is the best way to achieve this under these requirements:
User credentials for a 3rd party app need to be stored in the desktop app
Lightweight/thin client - as our Backend does all the heavy lifting the Frontend should be as lightweight as possible and just communicate with the Backend via DDP
Currently only needed for Windows/Mac as the available canvas for our D3 visualizations and content needs a large screen. Tablet is ok but 95% of our user are on desktop as per Google Analytics
Is a PWA app storing the credentials mentioned in 1) eg in the Mac keychain?
Which of the two (PWA vs Electron) would be more lightweight for the initial load and for updates (you mentioned that the service worker caches files)?
Our app is a SPA so we don’t need different tabs or open additional windows (which PWA can’t do).
We do need reactivity for some of our UI elements though, so Mini-Mongo is handy here. On the other hand, as our app is focusing on collaboration and all the data is stored on our Backend where other users can alter it as well. Is that giving PWA a disadvantage?
Lastly point to compare both is Google Page Rank. We have a separate landing page (static on S3) which used to give us a performance of 99 (I guess we need to constantly optimize it )
but a PWA will be clearly getting a much higher page rank based on the fact alone that Google wants us to make it a PWA. But how will both work the Google Tag Manage/Google Analytics to capture sessions, bounce rates and page views?
If you or anyone else can share their experience and views about these points I’d be thankful.
@a4xrbj1 I think the desktop PWA would work very nicely for you I would stay just to try it out and see what you think, I bet you’ll be impressed
The login token generated by Meteor’s accounts package is stored in the browsers PWA app, localStorage, just like it is in a regular Meteor web-session, so the user remains logged in.
You have reactivity like you would with a Meteor app running anywhere, nothing changes. A PWA does not change anything about the way your normal app works, it just gives it “extra” capabilities and installable app versions. The main feature that speeds up a PWA is the caching of your .js assets in the “ServiceWorker” and the ServiceWorker enables the user to look at the “loaded” data in your app even if the user’s connection drops for some reason, so this is really nice user & speed improvement. ServiceWorkers are still a pretty new thing to have in all Modern browsers.
Bob, was talking about 3rd party login credentials here, not the Meteor one. I guess we have to find a nice package that stores it securely and encrypted in localStorage.
The Meteor password isn’t the concern, it’s against the T&C of the 3rd party organization to share user credentials, hence it needs to be stored only on the device but never on our servers.
I have a question Bob, can PWA be done as well on Meteor’s server side? We need to do some requests that if done on the client will get us CORS errors as the requests are done on a third party outside of our domains, so it is possible to do requests server side using PWA?
@mexin I use server side requests a lot on Meteor’s server side with the PWA features in place I have also done some client side requests previously, but also removed most of those due to CORS errors a while back. So now a request for me goes something like this:
client Meteor.call → server Meteor.method req → some api → server resp → client resp
To fire a server side request and return a result to the client over Meteor’s awesome DDP connection, I use async/await functions that typically look something like this:
let someClientResponse = await Meteor.callPromise('some.meteor.method');
I use Vue Methods on the client to fire the Meteor.callPromise()… it’s such an easy solution & API love it!
To use a Meteor.callPromise(), you’ll need the deanius:promise package Big thanks to @deanius for making this very convenient package, it’s great. This is not the only way to do async/await Meteor calls, but it certainly is the easiest & cleanest if you ask me
Also you might enjoy reading this article by @robfallows about using Promises on the Client w/ Meteor
And just so everyone knows how to think about a PWA, it really is your same web app with some extra features that make it installable on mobile & desktop devices. You just add a manifest.json file and a ServiceWorker.js file that instructs your app to cache certain assets sent from the server to the client. This just speeds up your app really & gives an end user an even better experience.
@admins is it possible to have a label for PWA, please.
PWA is growing in importance after Apple recently opened Push notification for this technology.