Ditch all the other ideas and go for the cra-append-sw. It will save you a lot of time and pain.
It's as simple as installing the package, creating the service worker file in your main folder, and modifying your start and build commands in package.json file like this:
"start": "cra-append-sw --mode dev --env ./.env ./custom-sw.js && react-scripts start",
"build": "cra-append-sw --env ./.env ./custom-sw.js && react-scripts build",
And then you make sure to register the separate service worker in dev mode:
if ('serviceWorker' in navigator) {
console.log('Trying to register custom sw');
navigator.serviceWorker
.register('./firebase-messaging-sw.js')
.then(function (registration) {
console.log('Registration successful, scope is:', registration.scope);
})
.catch(function (err) {
console.log('Service worker registration failed, error:', err);
});
}
If like me you need access to environment variables in the service worker to initialize the firebase messaging module, this is the only simple option that doesn't require ejecting CRA.
I decided to post this answer because I myself overlooked the comments on the other answer and lost time unnecessarily looking for this solution.