firebase / firebase-js-sdk

Firebase Javascript SDK
https://firebase.google.com/docs/web/setup
Other
4.8k stars 882 forks source link

Service worker is registered twice #7481

Closed nojaf closed 1 month ago

nojaf commented 1 year ago

Operating System

Windows 11

Browser Version

Chrome/114

Firebase SDK Version

10.0.0

Firebase SDK Product:

Messaging

Describe your project's tooling

Plain ES6 with importmap (getting Firebase from https://esm.sh)

<script type="importmap">
    {
        "imports": {
            "fable-library/": "https://esm.sh/fable-library@1.1.1/",
            "react": "https://esm.sh/react@18.2.0",
            "react-dom": "https://esm.sh/react-dom@18.2.0",
            "usehooks-ts": "https://esm.sh/usehooks-ts@2.9.1?exports=useCopyToClipboard,useMediaQuery",
            "firebase": "https://esm.sh/firebase@10.0.0",
            "firebase/app": "https://esm.sh/firebase@10.0.0/app",
            "firebase/auth": "https://esm.sh/firebase@10.0.0/auth",
            "firebase/firestore": "https://esm.sh/firebase@10.0.0/firestore",
            "firebase/storage": "https://esm.sh/firebase@10.0.0/storage",
            "firebase/functions": "https://esm.sh/firebase@10.0.0/functions",
            "firebase/messaging": "https://esm.sh/firebase@10.0.0/messaging",
            "react-firehooks/auth": "https://esm.sh/react-firehooks@2.5.0/auth",
            "react-firehooks/firestore": "https://esm.sh/react-firehooks@2.5.0/firestore",
            "@iconify/react": "https://esm.sh/@iconify/react@4.1.1",
            "react-router-dom": "https://esm.sh/react-router-dom@6.14.1",
            "use-sync-external-store/shim": "https://esm.sh/use-sync-external-store@1.2.0/shim",
            "react-map-gl": "https://esm.sh/react-map-gl@7.1.1",
            "react-use": "https://esm.sh/react-use@17.4.0?exports=useGeolocation",
            "react-webcam": "https://esm.sh/react-webcam@7.1.1"
        }
    }
</script>

Describe the problem

My service worker is being registered twice for some reason:

image

I'm registering the service worker myself (with { "type": "module" }) using:

export function registerServiceWorker() {
    const matchValue = navigator.serviceWorker;
    if (matchValue != null) {
        const serviceWorker = matchValue;
        const options = { "type": "module" };
        return serviceWorker.register("/firebase-messaging-sw.js", options);
    }
    else {
        return Promise.reject(new Error("Service worker not available"));
    }
}

export function getFcmToken() {
    return PromiseBuilder__Run_212F1D4B(promise, PromiseBuilder__Delay_62FBFDE1(promise, () => (messaging_1().then((_arg) => {
        const messaging = _arg;
        return registerServiceWorker().then((_arg_1) => {
            const registration = _arg_1;
            return getToken(messaging, {
                serviceWorkerRegistration: registration,
                vapidKey: "...",
            });
        });
    }))));
}

but when I open another SPA route (where my messaging code isn't even used), I get the

Uncaught SyntaxError: Cannot use import statement outside a module (at firebase-messaging-sw.js:1:1)

message.

This makes sense as my actual firebase-messaging-sw.js looks like:

import {initializeApp} from "https://esm.sh/firebase@10.0.0/app";
import { getMessaging, onBackgroundMessage } from 'https://esm.sh/firebase@10.0.0/messaging/sw';

const firebaseConfig = { ...};

const app = initializeApp(firebaseConfig);

// Retrieve firebase messaging
const messaging = getMessaging(app);

function onMessage(payload) {
  console.log('Received background message ', payload);
  const { locationId, locationName, userName } = payload.data;

  const notificationTitle = "";
  const notificationOptions = {
  };

  return self.registration.showNotification(notificationTitle, notificationOptions);
}

onBackgroundMessage(messaging, onMessage);

I'm using import syntax there, so my SW needs type: "module" to work.

Steps and code to reproduce issue

I'm not quite sure how to draw out the actual problem. But some other firebase code is registering the worker again without the options.

I had in my file:

import { addDoc, Timestamp, collection, getDocs } from "firebase/firestore";
import { uploadBytes, ref } from "firebase/storage";
import { useAuthIdTokenResult, useAuthState } from "react-firehooks/auth";

and that shows the behaviour. But I do not get why.

nojaf commented 1 year ago

Ok, I've done some digging and I think I know where this is coming from. I can reliably reproduce the problem the moment I start executing a httpsCallable from "firebase/functions".

I'm able to patch my browser to always use "type": "module" when the service worker is registered:

<script>
    const originalRegister = navigator.serviceWorker.register;
    navigator.serviceWorker.register = function (scriptURL, options) {
      console.trace();
      options.type = "module";
      return originalRegister.call(navigator.serviceWorker, scriptURL, options);
    };
</script>

The trace showed my that:

image

Where getUsers is invoking httpsCallable.

jbalidiong commented 1 year ago

Hi @nojaf, thanks for reaching out. I tried replicating, but I wasn't able to reproduce the same behavior. One thing to note is that this may be a race condition on the manual registration and the SDK's auto registration. I would suggest trying to remove the block of codes for navigator.serviceWorker.register because internally the SDK runs that.

If the issue persists, please share a minimal, but complete sample of a project that I can run locally.

nojaf commented 1 year ago

Hi @jbalidiong, Thanks for looking into this. I'm off on vacation now, I might eventually come back to this and try and extract a sample from my codebase.

The race condition theory is quite likely the problem.

luisgurmendez commented 5 months ago

@jbalidiong Following this guide from firebase docs https://firebase.google.com/docs/cloud-messaging/flutter/receive#web for flutter at least. It says we should manually register the sw. I expect under the hood the package for flutter is using this library, so is this documentation wrong?

themightychris commented 2 months ago

It appears that flutter-messaging-sw.js gets loaded by the framework when you're debugging but doesn't when you build for release. So if you follow the instructions you get weird behavior with it loading twice while debugging. Has anyone seen it get loaded twice on release builds?

google-oss-bot commented 1 month ago

Hey @nojaf. We need more information to resolve this issue but there hasn't been an update in 5 weekdays. I'm marking the issue as stale and if there are no new updates in the next 5 days I will close it automatically.

If you have more information that will help us get to the bottom of this, just add a comment!

nojaf commented 1 month ago

Yeah, sorry for never reporting a proper sample that reproduces the issue. Long story short, I changed my code to not register the script myself.

hsubox76 commented 1 month ago

I'm going to close this for lack of a repro from the original user - if anyone else has this problem and can provide a repro, please feel free to open a new issue.