Progressive Web Apps (PWA) with Meteor

Hi Dan @dandv

Would this Google Chrome Labs library help?


Hello @dandv,

Back in 2017 I’ve explained with demo repo how to use Service Workers and implement PWA — here.
Also you might be interested to read this thread.


I was able to recently use the meteor build tool along with our heavily modified Node on FHIR stack to pass the Chrome Lighthouse PWA audit, which confirmed usage of service workers.

You can find the reference implementation here:


Hey guys, I added a full how-to-pwa step-by-step guide on Transform any Meteor App into a PWA - DEV Community 👩‍💻👨‍💻

Feel free to comment and raise issues :slight_smile:


I would advise on the use of Workbox and the solution offered here: I’d also like to note that the PWA solution in the article is outdated. If I would start today with PWAs I’d definitely look into 2020 technology and by this I am definitely not saying that the repo offered in the article is not valid.
Workbox is here:

As far as Meteor is concerned, one needs to understand what is to be offered to the user. Given the behavior of Minimongo and cacheing of actions, would I want to allow the user an offline experience?

Perhaps just show a screen letting the user know that he/she is not connected to internet.

How do I do PWA if I don’t use Minimongo and I do for instance Redux? How do I do Push (except Mobile Safari). What else can I load into the PWA environment?

I personally prefer (at least for the time being) not to return a 200 for the offline experience but others might be interested to do it.

I would suggest to start answering those question in a more official framework, here:
Would you want to own this section alone or with me or someone else?

It would be great if we could find all Meteor tips and documentation within the Meteor resources and link from there to other articles, tutorials instead of having everyone struggling with google.


Hi @paulishca I think the hardest task will be to provide an unopinionated solution. For small scale projects is Apollo total overkill while enterprise scale may not consider Meteor without Apollo. Also does pwa not necessarily require offline experience, although this would be great. However offline caching would require a way more sophisticated strategy than just pub/sub.

However, the offline topic is still a great improvement to the article and I will consider it for a follow-up. Regarding the 200 response - this is required by the audit, if you provide a different response your automated lighthouse audit would fail. Is there any resource concerning a different response when offline?

1 Like

@paulishca I checked the workbox and the strategy pattern looks promising :slight_smile: Am I bound to use their service worker file (afaik I am required to register workbox via sw) or can I inject workbox using my own sw file?

I can give you the entire configuration. Up to Workbox 4.x you could only do an importScript. As of V5, you can install it via NPM and use import {…} from ‘workbox/something.’
How can I pass this to you? Should I copy cod in this conversation here?

I think that should be okay to post it here, since the topic is overall about pwa so the others might be interested in it, too.

1 Like

Ok, I created a repo and a few comments:

  1. This is based on and most of the comments in the swSrc.js file belong to the original creator.
  2. The file mentioned about contains a demo for Push Notifications which has been tested with activitree:push. This part needs adaptation for anyone’s needs/flow.
  3. Procedure: you update the swSrc.js file and then run the scrip in the package.json. That script updates the sw.js in the public folder. It is wrong to edit sw.js directly.
  4. From the comments in swSrc.js you will understand what are the Meteor particularities. At the existent configuration you will probably want to add the bits for the 200 response, probably an extra route with an offline condition (the helper is provided by Workbox).
  5. I didn’t want to load this in the JS bundle so I prefer to use import script.
  6. There are very useful options to catch any kind of files, with expiration dates etc.
  7. This configuration should already satisfy the swapping of JS and CSS bundle files when new hashes are found.
  8. I have this in production with my under-construction project in case you want to give it a try. (

@jkuester I feel both our versions do all most nothing because they use the same wrong concept and functions. It could be that the workbox solution was written following the repo that you quoted.

This means that once a bundle file is eventually saved in the cache storage it will never be replaced with a new bundle because there is no way to compare.
Please tell me if I am wrong.

I think I finally managed to get it right with an almost complete rewriting. You can have a a look here: (I link to this page because it has very few assets and does not pollute workbox log too much). I enabled full Workbox debug for you so you can see some of the things that are going on.

In the Network console you can see the bundle files are being served from the Worker (or from the local cache, whatever the browser prefers). When new bundle files are detected, they are being server from the network and the local ones are overwritten.
All pages visited get cached so that when you open the app and there is no net it looks like … there is :slight_smile: … a behavior that I do not encourage unless you make a Spotify with offline files, offline maps, etc.

I will implement another strategy today which serves a locally cached HTML when offline.

The functions which I believe to be wrong:

function removeHash(element) {
  if (typeof element === 'string') return element.split('?hash=')[0];

function hasHash(element) {
  if (typeof element === 'string') return /\?hash=.*/.test(element);

function hasSameHash(firstUrl, secondUrl) {
  if (typeof firstUrl === 'string' && typeof secondUrl === 'string') {
    return /\?hash=(.*)/.exec(firstUrl)[1] === /\?hash=(.*)/.exec(secondUrl)[1];


Do you mean this one: ?

This means that once a bundle file is eventually saved in the cache storage it will never be replaced with a new bundle because there is no way to compare.

In the Network console you can see the bundle files are being served from the Worker (or from the local cache, whatever the browser prefers). When new bundle files are detected, they are being server from the network and the local ones are overwritten.

Did you create the bundle cache using workbox or did you extend the service worker?

Yes, that’s the repo I meant.
It is all Workbox. I am pushing to the existing repo in the next minutes.( )

Can you think of a workbox-independent solution? No offense against the tech, I rather think of the technical debt here, since there still needs to be a pwa integration for Meteor in general, which has to work for all setups (from classic DDP apps to modern graphql stacks). I think the build caching is something, that applies to all Meteor apps. wdyt?

Edit: From what I see in your sw file, I think it should not be that hard to write sw that supports several strategies, which also allows to inject thirdparty libs like workbox.


Relevant to this discussion – a sample app (non-Meteor) documenting PWA capabilities available today. Lots of good stuff.


One general question on this: Is it possible to use PWA‘s offline features without adding the app to the Home Screen and running it from there? I have a use case where the Meteor webapp runs inside the web view of a native mobile app, pretty much like Meteor’s Cordova approach, but without Cordova. It would be great if that webapp part would support offline use.

What specific offline features you referring to?

Just being able to use the app offline, i.e. if the server cannot be reached because of bad network conditions. I don’t need any integrations with native features, as this is already provided by the native shell (based on Unity, in my case). So, I basically need:

  • caching of the whole (React) app, once it has been downloaded from the server for the first time
  • a user who is still signed in locally (based on an existing token), even if the connection to the server breaks or cannot be established on app start
  • some way of caching locally generated MongoDB data until it can be synced with the remote server again

This was / is possible to some extent with a Cordova-based app, because Meteor is using a local web server internally. I was wondering if the same could be achieved by implementing service workers.

(If this is not clear enough, and you want to better understand our use-case: you can find our app as Marble Moments in the app stores. It allows you to leave photo and video memories in the real world. Currently, you have to be online do this. If you’re on a remote hiking trip, it won’t work anymore.)

It is possible since those are all browser powered featured.

The browser keep minimongo data in memory until it closed, the main issue is when happen this, so when it reopen without network it haven’t data.
Obviously service worker are necessary, because keep static data.
I’m working on completly offline app, the main idea is to save minimongo data in localstorage for getback when come online.
I’m tried with GroundDB but seems to complicated and I want a simple way to do it.
I want to manage also conflict data, when chenged in offline mode are made and at the moment of syncronizing is not equals.
I think I’m a good point, when it’s ready I would make a post with all descrpitions.