Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FCM integration/service-worker registration #1481

Open
kevguy opened this issue Jun 6, 2018 · 24 comments
Open

FCM integration/service-worker registration #1481

kevguy opened this issue Jun 6, 2018 · 24 comments

Comments

@kevguy
Copy link

kevguy commented Jun 6, 2018

What problem does this feature solve?

I used vue-cli to create a Vue app for development and so far the experience has been great. However, I also wanted to add FCM support to it which requires me adding a service worker. I have been working on the integration for two days but I still don't know how to do it and register the service worker properly.

I've tried adding a new service worker firebase-messaging-sw.js inside the public folder and register it in App.vue using

const registration = await navigator.serviceWorker.register(`${process.env.BASE_URL}firebase-messaging-sw.js`)
messaging.useServiceWorker(registration)

which works but then I'll have two service workers.

Then I modified vue.config.js to use this service worker instead:

module.exports = {
  pwa: {
    name: 'My App',
    themeColor: '#4DBA87',
    msTileColor: '#000000',
    appleMobileWebAppCapable: 'yes',
    appleMobileWebAppStatusBarStyle: 'black',

    // configure the workbox plugin
    workboxPluginMode: 'InjectManifest',
    workboxOptions: {
      // swSrc is required in InjectManifest mode.
      swSrc: 'public/firebase-messaging-sw.js'
      // ...other Workbox options...
    }
  }
}

Then I encounter errors like The script has an unsupported MIME type ('text/html').

I've checked Workbox's guides, @vue/cli-plugin-pwa but I still can't make it work. Can someone show me how to do the integration, cause I really don't know how to do it.

This discussion seems really close to what I'm asking for (vuejs-templates/pwa#27).

I also asked the question on StackOverflow (https://stackoverflow.com/questions/50711933/vue-cli-3-and-firebase-service-worker-registration)

What does the proposed API look like?

I should be able to have a correct config to do FCM integration.

@LinusBorg
Copy link
Member

  1. This is not a feature request.
  2. It might be a bugreport, but you didn't follow the issue guidelines, which require a runnable reproduction
  3. It isn't even a bug report, really, since you are asking how to solve your specific problem.
  4. Github issues are strictly reserved for feature requests and bug reports.

@kevguy
Copy link
Author

kevguy commented Jun 6, 2018

First, I think it can be both. Why I think it's more of a feature request is I need an API to merge a custom service worker to the one Vue provides. There's a registerServiceWorker.js and vue.config.js which I think are the most relevant places where I should edit my code.

I can't tell whether it should be a bug report or feature request because

  • I don't see any documentation about register-service-worker in registerServiceWorker.js unless you count the the sample config placed register-service-worker's README.md.
  • I do find something about service worker about how to edit vue.config.js, but it didn't mention how I should register it properly (especially with FCM which requires firebase.messaging().useServiceWorker())
  • Because of the lack of documentation and lack of answering on GitHub issues and StackOverflow questions, I can't tell whether it's a bug or it's a new feature I have to request, or the solution is actually pretty simple and all I need to do is add some code.

Second, runnable reproduction is simple enough I thought I didn't need to explicitly provide any. The replication step is simple:

  1. you have js file as a service worker, the content don't matter
  2. you register that service worker without getting errors like The script has an unsupported MIME type ('text/html')..

Third, I'm not even asking for a solution to solve a specific problem for myself, I asked for a way to register a service worker with or without using registerServiceWorker.js because some people may need to do the navigator.serviceWorker.register manually, much less FCM. And notice the title, I didn't say "FCM Integration", I added a "/service-worker registration" next to it.

For

const registration = await navigator.serviceWorker.register(`${process.env.BASE_URL}firebase-messaging-sw.js`)
messaging.useServiceWorker(registration)

My purpose was to illustrate what I need was not merging multiple service workers, but I also needed to make use of the registration.

As for the vue.config.js part, I illustrated I already did what I could do by reading the scarce documentation I could find.

Fourth, I found it disappointing that instead of at least pointing me to the right direction to find a solution myself, you are more fixated on whether it's a bug report or feature request because a strict policy triumphs everything. Before I opened an issue, I already looked at all the relevant issues here:

I even asked a question on StackOverflow and included a discussion from vuejs-templates here.

I'm not asking for handouts, I just want to make the app work, and opening issue here is what I thought I had to after trying different things for two days. Yet because of a "strict" policy I got shunned down. Thank you very much.

@LinusBorg
Copy link
Member

LinusBorg commented Jun 6, 2018

I need an API to merge a custom service worker to the one Vue provides.

You have it. You just misunderstood the documentation, which, I have no problem admitting, has to be refined until we leave beta.

You asked for a hint:

  1. simply leave register-service-worker untouched
  2. use InjectManifest mode (you already do).
  3. set swSrc in the pluginOptions to the source of your servericeWorker File in /src, not public
  4. don't try to register the service worker yourself, that's what vue-cli takes care of.

If you need more help, please use the appropriate channels, like the forum where I'm very active.

Second, runnable reproduction is simple enough I thought I didn't need to explicitly provide any.

We explain in detail why we ask for runnable reproductions on new-issue.vuejs.org, which you probably have read. This situation is not an exception.

You might think that it's easy to repoduce with the things you shared, but we have so, so many issues where people thinbk they showed us everything requried, only to find out after much work that the problem was in some other change they did, or forgot to show/share.

We simply refuse to put in this unnecessary work and waste time with it.

Fourth, I found it disappointing that instead of at least pointing me to the right direction to find a solution myself, you are more fixated on whether it's a bug report or feature request because a strict policy triumphs everything.

I understand that you are a bit frustrated about being stuck, and I'm sorry for that. But in order to keep the work that we do manageabe, we have a strict process in place.

You filled out the issue template, in which we explain there we have both a dedicated forum and a dedicated chat, which should be used to address questions about usage. We are active in both. You ignored that and opened and issue without trying these sources first, because you didn't get a reply on SO within a few minutes to an hour (I compared timestamps, you did both posts 7-8 hours ago).

@yyx990803
Copy link
Member

A strict policy is what keeps the project manageable. If we make an exception for everyone (and everyone will have an excuse somehow), we'd be just replying to issues all day without getting any real work done.

@bwcgn
Copy link

bwcgn commented Jun 18, 2018

@LinusBorg

simply leave register-service-worker untouched
use InjectManifest mode (you already do).
set swSrc in the pluginOptions to the source of your servericeWorker File in /src, not public
don't try to register the service worker yourself, that's what vue-cli takes care of.

Did all of this, after a build, it can not find service-worker.js

@LinusBorg
Copy link
Member

LinusBorg commented Jun 18, 2018

Feel free to start a topic on forum.vuejs.org and we 'll see how to help.

No support in issues.

@kevguy
Copy link
Author

kevguy commented Jun 19, 2018

@bwcgn

As long as an explicit registration of the service worker is required, what @LinusBorg said doesn't work. I finally sort of made it work by ditching registerServiceWorker.js and making the following changes:

First, in vue.config.js, specify where your service worker is (in my case, it's src/firebase-messaging-sw.js):

module.exports = {
  pwa: {
    // configure the workbox plugin
    workboxPluginMode: 'InjectManifest',
    workboxOptions: {
      swSrc: 'src/firebase-messaging-sw.js'
      // ...other Workbox options...
  }
}

The original service worker Vue uses will be injected into your service worker later. Therefore, all you need to do is register your service worker like how you used to:

navigator.serviceWorker.register(`${process.env.BASE_URL}firebase-messaging-sw.js`)

After the changes, the only differences I found were Chrome wouldn't automatically pop up and ask if I want to add my app to home screen. And after adding the app to the home screen, there's a chrome icon on it.

Note that I've already tried registering Firebase inside registerServiceWorker.js, but since I'm only registering my service worker if an user is authenticated, which I found I couldn't. Therefore, you can also try

register(`${process.env.BASE_URL}firebase-messaging-sw.js`, {
  ready () {
    console.log(
      'App is being served from cache by a service worker.\n' +
      'For more details, visit https://goo.gl/AFskqB'
    )
  },
  registered (registration) {
    // MAKE USE OF REGISTRATION HERE
  },
  // ...
})

I'm listing the solution here because I basically found a workable solution, starting a topic on forum.vuejs.org and post the solution doesn't seem too necessary.

@LinusBorg
Copy link
Member

LinusBorg commented Jun 19, 2018

Thanks for sharing this. I'm bit suprised that in your case, you say that no service-worker.js file was created, but a firebase-messaging-sw.js?

Because according to the docs of the workbox-plugin, unless you set swDest:, the default name for the bundled worker file is service-worker.js - both for GenerateSW and InjectManifest modes:

https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin#injectmanifest_plugin_1

And that's what my recommendation was reyling upon

Your code snippet mentions // ...other workbx options ....

Did you by any chance set swDest to firebase-messaging-sw.js? Or is the workbox doc incorrect here, and it infers the bundled worker filename from the sourcefile for InjectManifest Mode?

@kevguy
Copy link
Author

kevguy commented Jun 19, 2018

@LinusBorg I just tested it and the generated filename is not service-worker.js but what I specified, i.e. firebase-messaging-sw.js. I changed the filename a few times and the bundled worker is still generated in the dist folder with the same filename. So maybe the workbox doc is incorrect, but I don't know enough to tell. You can also refer to what I exactly wrote in vue.config.js here: https://github.com/kevguy/My-Shitty-Music-Frontend/blob/master/vue.config.js

Should I just add swDest or simply leave it be?

@LinusBorg
Copy link
Member

Thanks for the feedback. We probably should test this a bit more and adjust the generator that creates the register-service-worker.js file to reflect the behaviour.

@LinusBorg LinusBorg reopened this Jun 19, 2018
@1337erik
Copy link

1337erik commented Jul 6, 2018

im finding this after tons of digging on how to answer the same question,
to put it more concisely:
how do we use the registered service worker once this vue-cli generated boilerplate code registers it.

there is zero documentation on what to do with this, and if anyone could just post a few code examples of grabbing the registration object ( or whatever ) and doing something productive with it ( like sending a push notification or caching something ) they'd be a vuejs hero.

moved this to a stack overflow post: https://stackoverflow.com/questions/51214220/vue-cli-3-how-to-use-the-official-pwa-plugin-service-worker

@LinusBorg
Copy link
Member

LinusBorg commented Jul 6, 2018

@1337erik

Let's do the following: I'll walk you through the path of the documentation as I see it to answer your questions, trying to acknowledge missing pieces along the way, and you comment on that, adding information about what else is missing in your opinion, what could be made more clear, and what you may have missed when you asked your original question because said path wasn't clear.

That way, we can identify spots where we have to improve the docs.

Preface:

I don't think that it's the job of the vue-cli documentation to explain

  • What service workers are
  • how they work
  • how to interact with a registered service-worker in general and what to do with it.

What we should do:

  • Clearly document all the options of the PWA plugin
  • Clearly state what other pieces of software are involved and what additional 3rd party documentation may be helpful to get hands-on with the service-worker created by this plugin.

Walkthrough

  • The documentation on cli.vuejs.org links to the README in the pwa directory for documentation of the plugin. I think that's justified for the moment as documenting each plugin in detail on cli.vuejs.org directly, before releasing 1.0.0, would put a serious delay on the project
  • In that README, it's explained that service workers are actually created with the workbox-webpack-plugin, and that there are two different modes to create a service worker - GenerateSW and InjectManifest. We link to a section of the Workbox documentation to help you decide which to pick. Did you read it?
  • If you read that linked documention, you will have realized that you can't do anything with the default serviceworker, created with the GenerateSW option, because all it does is cache files according to the given options, and you can't add any code to it.
  • So now we know that to actually use our own code in a serviceworker, we will have to use the InjectManifest option.

It's here that we come to the original problem of this issue: When using this mode, the name of the generated serviceworker reflects the name of the source file, which breaks the currently defined import in ./registerServiceWorker.js.
I already acknowledged that we have to improve that part of the plugin, either in the code or the documentation.

So let's assume you

  1. successfully created your custom serviceworker file,
  2. activated InjectManifest option as expained in the plugin's README (are those instructions clear enough after having read about workbox & its webpack-plugin? If not, what would be required to connect the dots?)
  3. and the import in the ./registerServiceWorker.js file was working.

The question that you are left with, and that you asked here, is how to interact with this serviceworker.

I think we should:

  1. Link to the README of the register-service-worker package that the plugin is using
  2. explain more clearly (in that README, but probably also in the ./registerServiceWorker.js file that the plugin creates, in comments) what most of the methods in that file return:

A ServiceWorkerRegistrationObject (see MDN). We should probably link to that MDN documentation from a comment in the file.

With that Object, you get access to all of the serviceworker features, and I think we stop exactly here. As expained in the preface, teaching how to use service-workers is out of scope for vue-cli.

Maybe the community steps in and writes a nice guide about cools stuff to do with your own service worker for our cookbook or their own blog, and we can then link to it, but other than that, educating yourself is your own responsibility.

Thougths?

@LinusBorg LinusBorg self-assigned this Jul 6, 2018
@1337erik
Copy link

1337erik commented Jul 6, 2018

Yes I think you hit the nail on the head, including pointing me in a solid direction to go from here. Thank you.

To answer your comment: yes, I did read through all of those documents already.

What you just said:

If you read that linked documention, you will have realized that you can't do anything with the default serviceworker, created with the GenerateSW option, because all it does is cache files according to the given options, and you can't add any code to it.
So now we know that to actually use our own code in a serviceworker, we will have to use the InjectManifest option.

is excellent, it answers the question, but is by no means as self explanatory as you make it out to be.

maybe I'll upload some solutions myself once I work through this.

@LinusBorg
Copy link
Member

LinusBorg commented Jul 6, 2018

Note that "can't do anything" might be a bit exaggerated - you still get acces to the same Registration object and all of its options. But since you can't add your own code to that service-worker, it is of limited usefulness imho.

[...] but is by no means as self explanatory as you make it out to be.

That's more of a problem with the workbox documentation, isn't it? We also don't say a word about how to use typescript, eslint, jest, or any of the other tools that vue-cli adds for you, for good reason.

I'm happy to add a small paragraph to the plugin's README (or accept a PR for one), but that must be it.

@1337erik
Copy link

1337erik commented Jul 6, 2018

I just read the part on the workbox doco that mentioned needing 'injectManifest' for any other PWA functionality. Its one of those moments where my eyes glaze over text and it just doesn't register in my mind what it really means -.-

@safu9
Copy link

safu9 commented Jul 11, 2018

It looks like default swDest will have the same file name as swSrc in injectManifest mode only.

https://github.com/GoogleChrome/workbox/blob/master/packages/workbox-webpack-plugin/src/inject-manifest.js#L60

@LinusBorg
Copy link
Member

@safu9 yep, that's why your dwfault implementation still works.

@hubierti3
Copy link

I have similar problems, however I noticed that when is npm run serve, I get no firebase-messaging-sw.js, only the service worker, WITHOUT my code. When I build, even though I don't specify swDest, no service-worker.js and only firebase-messaging-sw.js.

@liveangela
Copy link

liveangela commented Aug 19, 2018

So let's assume you

  1. successfully created your custom serviceworker file,
  2. activated InjectManifest option as expained in the plugin's README (are those instructions clear enough after having read about workbox & its webpack-plugin? If not, what would be required to connect the dots?)
  3. and the import in the ./registerServiceWorker.js file was working.

Through all these three steps, we can successfully create our own sw.js file in prodution mode.
But there exits other problems like:

  1. how could it be used in development mode(maybe work around like this)
  2. how could it be used with preprocess lang such as Typescript to create sw.js file

Actually the sceond one may be the Webpack work flow problem,

  • firstly, create a .ts file which includes some other imported modules under src/
  • secondly, use Webpack to transform this file(ts-loader and uglify) into sw.bundle.js
  • lastly, set pwa property swSrc: 'sw.bundle.js' in vue.config.js

but it really confuses me that how to make this work,
how to set the vue-cli property configureWebpack or chainWebpack

@mrsalitre
Copy link

mrsalitre commented Oct 17, 2018

@kevguy My solution after read all this:

The file registerServiceWorker.js in /src register a service worker call service-worker.js.

But.

If you add configuration in your vue.config.js more specifically the pwa plugin workboxPluginMode and workboxOptions and use swSRC: "src/firebase-messaging-sw.js" the service-worker.js now is firebase-messaging-sw.js. In /src/registerServiceWorker.js the default vue cli configuration register a 'service-worker.js', change that register name with firebase-messaging-sw.js and voilá!

Anyway, I have a lot of doubts, for example. If I use injectManifest, to use firebase-messaging-sw.js, what am I losing by not using the default service-worker.js? Or injecting simply adds the functions of firebase-messaging-sw.js to that default setting? which would mean that all the cache control is intact and would let me sleep well.

@gwaihir8
Copy link

gwaihir8 commented Dec 5, 2018

hi guys, I also struggled with doing some extra things with custom service workers. Now I wrote a small guide on how to use Vue PWA with a custom service worker and how to get:

  • install button triggering chrome's install notification
  • triggering a 'new content' popup.

https://medium.com/@kobededecker/vue-pwa-example-298a8ea953c9

@OwenMelbz
Copy link

@LinusBorg Hi - are you able to explain what the expected development process would be for this?

Lets say I've added the following to a src/service-worker.js and registered it via pwa.workboxOptions.swSrc in the vue.config.js file along with workboxPluginMode: 'InjectManifest',

console.log('im here');

self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

When we run npm run build -- obviously this compiles into the dist directory and we can then service that somehow.

-- That is all fine for production/testing it out

BUT....

How are we meant to use the vue cli to develop this file efficiently? e.g. we have npm run serve which auto-reloads everything - but when thats running process.env.NODE_ENV is development so the registerServiceWorker doesn't run thus you don't get any feedback from the SW.

The only way I can get any form of it working is by running npm run build this will create the dist/service-worker.js - then editing the dist file - regularly copy/pasting it back into src/service-worker.js then running the build command again?

This obviously doesn't seem optimal - and I think maybe what many people are also struggling with as the docs don't currently explain the development process in the same way as it explains many of the others.

What would you consider to be the solution to this? or a suggested process to have this working as efficiently as possible?

Many thanks :)

@rstormsf
Copy link

rstormsf commented Feb 5, 2019

@gwaihir8 I don't understand why I can't register an event on notificationclick
in sw.js

self.addEventListener('notificationclick', function(event) {
  console.log('notificationclick', notification)
  var notification = event.notification;
})

@gwaihir8
Copy link

gwaihir8 commented Feb 5, 2019

@rstormsf Because the service-worker lives in a separate process and can't register browser events directly. Capture the event in the browser (easiest in the register-serviceworker.js, this one does live in the browser) and send a message to the service worker (using the postMessage function).

@LinusBorg LinusBorg removed their assignment Aug 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests