I recently had to do this with a CRA app, it's not easy to find information on it so I figured I should share my solution. Assuming you've already changed serviceWorker.unregister()
to serviceWorker.register()
in ./src/index.js
, and have a .env
file with your variables set in the root of your project, then you can update ./src/serviceWorker.js
to include your process.env
variables as a query string.
In the register
function in serviceWorker.js
, update const swUrl
as shown below, notice the const firebaseConfig
w/process.env, declared before swUrl
..
./src/serviceWorker.js:
// Convert environment variables to URL `search` parameters
const firebaseConfig = new URLSearchParams({
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID
}).toString();
// Service worker URL w/config variables
const swUrl = `${process.env.PUBLIC_URL}/firebase-messaging-sw.js?${firebaseConfig}`;
then in ./public/firebase-messaging-sw.js
(create it if it doesn't exist), you can do something like the following..
./public/firebase-messaging-sw.js
importScripts('https://www.gstatic.com/firebasejs/8.0.2/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.0.2/firebase-messaging.js');
// Set Firebase configuration, once available
self.addEventListener('fetch', () => {
const urlParams = new URLSearchParams(location.search);
self.firebaseConfig = Object.fromEntries(urlParams);
});
// "Default" Firebase configuration (prevents errors)
const defaultConfig = {
apiKey: true,
projectId: true,
messagingSenderId: true,
appId: true,
};
// Initialize Firebase app
firebase.initializeApp(self.firebaseConfig || defaultConfig);
const messaging = firebase.messaging();
// Configure message handler (assumes backend is set up)
messaging.onBackgroundMessage((payload) => {
const { icon, body, title } = payload.data;
self.registration.showNotification(title, { body, icon });
});
If there's a more ideal solution, would love to hear about it, but this configuration worked for me.