What do you expect from your Meteor PWA (Draft here: https://github.com/activitree/Meteor-PWA-Explained)

I have thoughts on this! But it’ll take me a minute to compile everything, so here’s just a couple of off the cuff random comments:

PWA is very doable now, given all existing tech. PixStori is a PWA (with one caveat below). The only real thing missing is a service-worker. There is one - I have a version in my starters. This service workers really only solves a sub-set of what you might want to solve with a service worker- mainly it captures the main js and css bundles. In order to get everything else cached for offline use, you might need to enable appcache, which aside from enabling the legacy and deprecated appcache browser feature, also prefetches and caches all dynamic modules.

The truth is, most of what you might need a Service Worker for is taken care of in other ways in Meteor, so we probably don’t need a super complex one. It’s also the kind of thing that developers might want to take the care to write and understand themselves, rather than using something generic.

Some things that are missing off the top of my head (but which are probably achievable without a TON of effort)

  • a way to capture a app shell when SSR is enabled, instead of capturing an SSR html page, which may contain outdated data, and other problems.
  • Push notifications - it’s own whole thing.

PWA manifests and the like can all be created by external tools. Meteor could have a thing built in to do that (similar to Cordova), but I actually prefer it this way. Your mileage may vary.

One problem I do have, is that I have a memory leak with my SSR code but only in production (which I think is related to mix of Fibers/Futures and React hooks/fibers - different fibers), which has been difficult to trouble shoot on Galaxy. What I probably need to do is learn enough devops to get a production build up and running in a Docker container (I got this far), and then run some tools on that to figure it out (working on this). But there’s a reason I use Galaxy. Hopefully the ability to hook up a debugger to Galaxy instances is coming. Currently SSR is disabled on PixStori because of this, which also disabled necessary features like open graph, etc.

(I’m probably mixing up some offline-first stuff with PWA here)

2 Likes

PWA’s are a very interesting thing. We have been using it with Meteor for around 2 years, creating dinamically a PWA for each one of our clients. We dont have SSR but we use server-render package to send the open-graph and other metatags to the client without issues. In our case the service worker does almost nothing, just get the bundle and for push notifications in Chrome.

I dont remember what else we had to do to get PWA working, but it was a couple of hours of work. I was tempted to create a package for this, but not having the app working offline hold me on that.

1 Like

Hi,

thank you for your inputs and will be looking forward to enjoy your contributions on the “official” documentation. I don’t expect V1 to be clean and free of mistakes, misspells and confusions but as more users try to read and implement it, things will get explained better and better.

As far as I know there are three different Push packages for Meteor: RAIX, Rocket.Chat and Activitreee:Push. I think Activitree:Push is the only one that fully relies on Firebase Admin SDK for Notifications instead of using 2 different services (one for IOS and another one for Android).

I will write the Push Notification for PWA in direct entanglement with Activitree:Push while I will maintain compatibility with the other Push packages (if they support WebPush).

“I’ll be back” in 2-3 days with a first draft.

Thank you

2 Likes

So there is no way for push notifications that completely works without vendor lock-in?

@jkuester What is a vendor lock-in in this case? I mean, where do you perceive a locking?

Ideally, the package is a minimum structure that checks the minimum requirements for a PWA.

On top of my head, this will include the basics of handling the basic events like install, fetch, and activate.

Then maybe the rest are through extensions or plugins. This part should include things like:

  • handling custom install prompt
  • handling push
  • handling data caching outside of Meteor assets
  • etc.

So this can give enough options to the developers on how to go about these parts which most likely is different for each application

“these parts which most likely is different for each application” - perhaps this is why a documentation/tutorial is required and not a package.

This was a helpful read for the install prompt process:

Because I’m personally focusing on a Vue + Meteor app, that is how I’ll be implementing some more PWA features ideally to get the very desirable “install” option in Chrome. This is a really nice tutorial that is helpful to read when exploring this implementation. No need for Auth0 with Meteor’s accounts packages obviously, but the rest of this tutorial is pretty relevant. It recommends a webpack plugin which would even be possible with Meteor, as many people have successfully added webpack to Meteor, although there are other ways of achieving this.

If anyone is building their own PWA implementations on Meteor, this would give you some things to think about.

If anyone working with Meteor & PWAs has time to look at this, it would be cool to get your thoughts on what parts you might consider keeping and what parts you would ignore.

I keep finding more great stuff on PWAs and the packages that are powering most of the PWA apps out there. I had been drilling down a little on the Service Worker (SW) options and found another Node.js SW solution, which does seem like it would be an ideal way to build a service worker for Meteor.

Google made a package on npm called workbox-build and it seems to do most of the heavy lifting, and is of course the most popular way to accomplish these tests at the moment from what I can tell, with over 2 mil npm download per week.

@jkuester would you mind taking a look at this package since you’ve got a good handle on how Service Workers might need to work with Meteor from the tutorial your wrote?

I’ll be trying this out soon on my project, but it would be great to see what everyone thinks of this approach.

Tag anyone here on the forums that is the most familiar with the Meteor build process to comment on how this workbox-build npm package might work? It has Babel dependencies, so to me it looks like it would be nicely compatible :+1:

3 Likes

We looked at the Workbox in the past and I believe it was @jkuester who suggested we should do it clean without further dependencies on other technologies.

1 Like

I think it is an in-between case. Some parts of Meteor bound to certain techologies (for example WebApp uses the connect api) and this should of course be reduced to a minimum.

I have not gathered an audit on the workbox packages to say how heavy this would couple us. However, I know from google, that they tend to let projects fall from one to day to another, making long term maintenance pure horror then.

On the other hand I see great potential in what workbox is offering and I think it should be discussed with Tiny (cc @filipenevola) which path this whole out-of-the-box PWA integration should go.

1 Like

Hi,

the first draft for implementing Meteor PWA with Push Notifications and Offline pages is here: https://github.com/activitree/Meteor-PWA-Explained.

I tried to detail as much as possible on every aspect. Looking forward to your corrections, feedback, suggestions etc.

7 Likes

Nice work @paulishca. I still need to wrap my head around the caching of the bundle but I am learning a lot

Some questions/feedback:

  1. Why are you calling self.clients.claim() for every fetch? It should be enough to call this on activate

  2. Better to handle PUT and POST event methods on fetch as only GET methods are being cached

  3. Why handle the fetch for robots.txt, sitemap.xml, etc. which is fetched by 3rd party systems from the server and not the service worker?

  1. What will happen to sockjs requests?
  1. 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()
          })
        }
  1. 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.

  2. 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.

  1. Check the explanation of clients.claim() here: https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle

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.

  1. event.request.method is either a GET, PUT, or a POST. Only a GET method can be cached.
    https://github.com/w3c/ServiceWorker/issues/693

  2. Still cannot wrap my head around why a client will fetch robots.txt and sitemap.xml from the server. Maybe you have a unique use case in your app

  3. Got it, thanks

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.

2 Likes

I would like a npm package to add into meteor, that will allow, in order of importance:

  1. Offline cache of used assets, to load page quickly, fast as a static page.
  2. Installable, proper desktop and loading icons. Ideally a hook to control this prompt.
  3. Offline cache of DB in local storage, ideally with mini mongo sync included.
  4. A guide to do all this and the rest.
1 Like