簡體   English   中英

如何在 React 服務工作者中使用 process.env

[英]How to use process.env in a React service worker

我正在嘗試設置 Firebase-messaging-sw.js 文件(用於 web 推送通知)。 我想知道是否有辦法避免將我的 Firebase 配置數據盡可能地暴露給公眾——盡管它可能會被泄露? (我不太確定細微差別)

我嘗試了以下方法: 如何根據環境變量自定義我的 Service Worker? 但是答案的 swEnvbuild 似乎沒有運行,因為沒有找到 swenv.js 文件。 我懷疑它可能需要在 React 中進行不同的設置?

(第一個問題,請隨時對我的問題提出建設性的批評)

我最近不得不用一個 CRA 應用程序來做這件事,要找到它的信息並不容易,所以我想我應該分享我的解決方案。 假設您已經在 ./src/index.js 中將 serviceWorker.unregister( serviceWorker.unregister()更改為./src/index.js serviceWorker.register() ,並且在項目的根目錄中設置了一個帶有變量的.env文件,那么您可以更新./src/serviceWorker.js將您的process.env變量包含為查詢字符串。

在 serviceWorker.js 中的register serviceWorker.js中,更新const swUrl如下所示,注意const firebaseConfig firebaseConfig w/process.env,在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}`;

然后在./public/firebase-messaging-sw.js中(如果不存在則創建它),您可以執行以下操作。
./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 });
});    

如果有更理想的解決方案,很想聽聽,但這種配置對我有用。

我發現這篇文章使用cra-append-sw到 append 環境變量。 然后我在package.json中創建了兩個pre腳本。 當我運行npm start腳本運行創建一個[root folder]/public/firebase-messaging-sw.js prestart環境變量的文件(在被 webpack 處理之后)。

執行

我創建了一個[root folder]/firebase-messaging-sw.js 此文件將由 webpack 處理,替換環境變量的值。

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

然后我有[root folder]/.env.dev[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...

最后,我在package.json中添加了 2 個pre腳本

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

我自己在這個問題上遇到了真正的麻煩。 服務工作者在您的環境啟動之前就參與了堆棧方式,因此它無權訪問您的.Env變量是有道理的。

我的解決方案

我構建了一個 npm 模塊,該模塊在構建時使用 webpack 從 your.env 文件中提取“安全”版本控制變量並將它們放入獨立的 JS 文件中。 然后,您可以提前 go 並導入此文件並在您的服務人員中使用它。

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

免責聲明:

我知道這是針對 vue 的,但它的 webpack,它不是 vue 特定的。 此外,您最好只復制代碼而不使用模塊。 這對我自己來說更像是一個有趣的練習:)

在 index.js 文件中(或任何你想注冊 service worker 的地方):

if ("serviceWorker" in navigator) {
  console.log("Registration started");
  const firebaseConfig = encodeURIComponent(
    JSON.stringify({
      apiKey: process.env.FCM_API_KEY,
      projectId: process.env.FCM_PROJECT_ID,
      messagingSenderId: process.env.FCM_SENDER_ID,
      appId: process.env.FCM_APP_ID,
    })
  );
  navigator.serviceWorker
    .register(
      `../../../firebase-messaging-sw.js?firebaseConfig=${firebaseConfig}`
    )
    .then(function (registration) {
      console.log("Registration successful, scope is:", registration.scope);
    })
    .catch(function (err) {
      console.log("Service worker registration failed, error:", err);
    });

在 Service Worker 中,firebase-messaging-sw.js:

importScripts("https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js");
importScripts(
  "https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js"
);

firebase.initializeApp(
  JSON.parse(new URL(location).searchParams.get("firebaseConfig"))
);

firebase.messaging();

這足以在發送通知類型消息時接收后台推送通知。

此解決方案將起作用,只需記住根據您的項目編輯 Service-worer 文件的路徑(在 index.js 左右注冊時),否則它會給出“Mime 錯誤”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM