8
votes

Comment utiliser process.env dans un service worker React

J'essaie de configurer un fichier Firebase-messaging-sw.js (pour les notifications push web). Je me demande s'il existe un moyen d'éviter d'exposer autant que possible mes données de configuration Firebase au public - même si cela peut être révélé de toute façon? (Je ne suis pas trop sûr des nuances)

J'ai essayé ce qui suit: Comment puis-je personnaliser mon Service Worker en fonction des variables d'environnement? Mais swEnvbuild de la réponse ne semble pas être en cours d'exécution, car le fichier swenv.js est introuvable. Je soupçonne qu'il pourrait avoir besoin d'être configuré différemment dans React?

(première question, n'hésitez pas à fournir des critiques constructives de ma question)


0 commentaires

3 Réponses :


1
votes

J'ai récemment dû le faire avec une application de l'ARC, ce n'est pas facile de trouver des informations dessus, alors j'ai pensé que je devrais partager ma solution. En supposant que vous avez déjà changé serviceWorker.unregister() en serviceWorker.register() dans ./src/index.js et que vous avez un fichier .env avec vos variables définies à la racine de votre projet, vous pouvez mettre à jour ./src/serviceWorker.js pour inclure vos variables process.env tant que chaîne de requête.

Dans la fonction register de serviceWorker.js , mettez à jour const swUrl comme indiqué ci-dessous, notez le const firebaseConfig w / process.env, déclaré avant swUrl .
./src/serviceWorker.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 });
});    

puis dans ./public/firebase-messaging-sw.js (créez-le s'il n'existe pas), vous pouvez faire quelque chose comme ce qui suit ..
./public/firebase-messaging-sw.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}`;

S'il y a une solution plus idéale, j'aimerais en entendre parler, mais cette configuration a fonctionné pour moi.


0 commentaires

0
votes

J'ai eu de vrais problèmes avec celui-ci moi-même. Le service worker s'implique dans la pile bien avant que votre environnement ne soit amorcé, il est donc logique qu'il n'ait pas accès à vos variables .Env .

Ma solution

J'ai construit un module npm qui, lors de la compilation, en utilisant webpack, extrait vos variables de contrôle de version "sûres" de votre fichier .env et les met dans un fichier JS autonome. Vous pouvez ensuite importer ce fichier et l'utiliser dans votre service worker.

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

Avertissement:

Je sais que c'est pour vue, mais son webpack, et ce n'est pas spécifique à la vue. De plus, vous feriez peut-être mieux de copier simplement le code et de ne pas utiliser le module. C'était plus un exercice amusant pour moi :)


0 commentaires

0
votes

J'ai trouvé cet article qui utilise cra-append-sw pour ajouter les variables env. Ensuite, j'ai créé deux pre scripts dans mon package.json . Quand prestart npm start le script de prestart - prestart s'exécute en créant un fichier [root folder]/public/firebase-messaging-sw.js qui contient les variables d'environnement (après avoir été traité par webpack).

Important: testé localement uniquement

Donc, je ne sais pas si cela fonctionnera en production. Je mettrai à jour cette réponse une fois que le travailleur sera en production. Je voulais d'abord soumettre ma réponse :)

la mise en oeuvre

J'ai créé un [root folder]/firebase-messaging-sw.js . Ce fichier sera traité par webpack en remplaçant les valeurs des variables env.

...
"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",
...

alors j'ai [root folder]/.env.dev et [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...

Et enfin, j'ai ajouté 2 pre scripts dans mon package.json

// 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);
});


0 commentaires