How to use process.env in a React service worker

杀马特。学长 韩版系。学妹 提交于 2021-01-26 05:36:28

问题


I am trying to set-up a Firebase-messaging-sw.js file (for web push notifications). I am wondering if there is a way to avoid exposing my Firebase config data to the public as much as possible - though it might be revealed anyways? (I'm not too sure about the nuances)

I've tried following: How can I customize my Service Worker based on environment variables? But the answer's swEnvbuild doesn't seem to be running, as the swenv.js file is not found. I suspect it might need to be set-up differently in React?

(first question, please feel free to provide constructive criticisms of my question)


回答1:


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.




回答2:


I had real troubles with this one myself. The service worker gets involved in the stack way before your environment gets bootstrapped so it makes sense that it doesn't have access to your .Env variables.

My Solution

I built an npm module that on build, using webpack, extracts your "safe" versioning variables from your .env file and puts them into a stand-alone JS file. You can then go ahead and import this file and use it in your service worker.

https://www.npmjs.com/package/vue-enverywhere

Disclaimer:

I know this is for vue, but its webpack, and it's not vue specific. Also, You might be better to just copy the code, and not use the module. This was more of a fun exercise for myself :)




回答3:


I found this article which uses cra-append-sw to append the env vars. Then I created two pre scripts in my package.json. When I run npm start the prestart script runs creating a [root folder]/public/firebase-messaging-sw.js file that contains the env vars (after being processed by webpack).

Important: Tested locally only

So I don't know if it will work in production. I will update this answer after I have the worker running on production. I wanted to submit my answer first :)

Implementation

I created a [root folder]/firebase-messaging-sw.js. This file will be processed by webpack replacing the values of the env vars.

// Give the service worker access to Firebase Messaging.
// Note that you can only use Firebase Messaging here. Other Firebase libraries
// are not available in the service worker.
importScripts('https://www.gstatic.com/firebasejs/8.1.1/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/8.1.1/firebase-messaging.js');

// Initialize the Firebase app in the service worker by passing in
// your app's Firebase config object.
// https://firebase.google.com/docs/web/setup#config-object
firebase.initializeApp({
    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,
});

// Retrieve an instance of Firebase Messaging so that it can handle background
// messages.
const messaging = firebase.messaging();
messaging.onBackgroundMessage(function (payload) {
    console.log('[firebase-messaging-sw.js] Received background message ', payload);
    // Customize notification here
    const notificationTitle = 'Background Message Title';
    const notificationOptions = {
        body: 'Background Message body.',
        icon: '/logo.png'
    };

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

then I have [root folder]/.env.dev and [root folder]/.env.prod

REACT_APP_FIREBASE_API_KEY=A...
REACT_APP_FIREBASE_AUTH_DOMAIN=d...
REACT_APP_FIREBASE_DATABASE_URL=h...
REACT_APP_FIREBASE_PROJECT_ID=d...
REACT_APP_FIREBASE_STORAGE_BUCKET=d...
REACT_APP_FIREBASE_MESSAGING_SENDER_ID=7...
REACT_APP_FIREBASE_APP_ID=1...
REACT_APP_FIREBASE_MEASUREMENT_ID=G...

And finally, i added 2 pre scripts in my package.json

...
"scripts": {
    "prestart": "cra-append-sw --mode dev --env ./.env.dev ./firebase-messaging-sw.js",
    "prebuild": "cra-append-sw --mode build --env ./.env.prod ./firebase-messaging-sw.js",
...


来源:https://stackoverflow.com/questions/62225339/how-to-use-process-env-in-a-react-service-worker

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!