從命名空間 API 升級到模塊化 API

當前使用任何命名空間 Firebase Web API(從compat庫到版本 8 或更早版本)的應用程序應考慮使用本指南中的說明遷移到模塊化 API。

本指南假設您熟悉命名空間 API,並且您將利用webpackRollup等模塊捆綁器來升級和正在進行的模塊化應用程序開發。

強烈建議在您的開發環境中使用模塊捆綁器。如果您不使用它,您將無法利用模塊化 API 在減小應用程序大小方面的主要優勢。您需要npmyarn來安裝SDK。

本指南中的升級步驟將基於一個使用身份驗證和 Cloud Firestore SDK 的虛構 Web 應用。通過完成這些示例,您可以掌握升級所有受支持的 Firebase Web SDK 所需的概念和實際步驟。

關於命名空間 ( compat ) 庫

Firebase Web SDK 有兩種類型的庫可用:

  • 模塊化- 一個新的 API 界面,旨在促進 tree-shaking(刪除未使用的代碼),使您的 Web 應用程序盡可能小和快。
  • 命名空間 ( compat ) - 一個熟悉的 API 界面,與早期版本的 SDK 完全兼容,讓您無需立即更改所有 Firebase 代碼即可進行升級。與命名空間對應的庫相比,兼容庫在大小或性能方面幾乎沒有優勢。

本指南假設您將利用兼容庫來促進升級。這些庫允許您繼續使用命名空間代碼以及為模塊化 API 重構的代碼。這意味著您在完成升級過程時可以更輕鬆地編譯和調試應用程序。

對於很少接觸 Firebase Web SDK 的應用程序(例如,僅對身份驗證 API 進行簡單調用的應用程序),在不使用兼容庫的情況下重構舊的命名空間代碼可能是實用的。如果您要升級此類應用程序,則可以按照本指南中的“模塊化 API”說明進行操作,而無需使用兼容庫。

關於升級過程

升級過程的每個步驟都有一定的範圍,以便您可以完成應用程序源代碼的編輯,然後編譯並運行它而不會造成任何損壞。總之,您需要執行以下操作來升級應用程序:

  1. 將模塊化庫和兼容庫添加到您的應用程序中。
  2. 更新代碼中的導入語句以兼容。
  3. 將單個產品(例如身份驗證)的代碼重構為模塊化樣式。
  4. 可選:此時,刪除身份驗證兼容庫和身份驗證的兼容代碼,以便在繼續之前實現身份驗證的應用程序大小優勢。
  5. 將每個產品(例如Cloud Firestore、FCM等)的功能重構為模塊化風格,編譯和測試,直到所有區域完成。
  6. 將初始化代碼更新為模塊化風格。
  7. 從應用程序中刪除所有剩餘的 compat 語句和 compat 代碼。

獲取最新版本的SDK

首先,使用 npm 獲取模塊化庫和兼容庫:

npm i firebase@10.3.1

# OR

yarn add firebase@10.3.1

更新導入以兼容

為了在更新依賴項後保持代碼正常運行,請更改導入語句以使用每個導入的“compat”版本。例如:

之前:版本 8 或更早版本

import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

之後:兼容

// compat packages are API compatible with namespaced code
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';

重構為模塊化風格

雖然命名空間 API 基於點鏈命名空間和服務模式,但模塊化方法意味著您的代碼將主要圍繞函數進行組織。在模塊化 API 中, firebase/app包和其他包不會返回包含包中所有方法的全面導出。相反,這些包導出單獨的函數。

在模塊化 API 中,服務作為第一個參數傳遞,然後函數使用服務的詳細信息來完成其餘的工作。讓我們通過兩個重構對身份驗證和 Cloud Firestore API 的調用的示例來看看它是如何工作的。

示例 1:重構 Authentication 函數

之前:兼容

兼容代碼與命名空間代碼相同,但導入已更改。

import firebase from "firebase/compat/app";
import "firebase/compat/auth";

const auth = firebase.auth();
auth.onAuthStateChanged(user => { 
  // Check for user status
});

之後:模塊化

getAuth函數將firebaseApp作為其第一個參數。 onAuthStateChanged函數不像命名空間 API 那樣從auth實例鏈接;相反,它是一個免費函數,將auth作為其第一個參數。

import { getAuth, onAuthStateChanged } from "firebase/auth";

const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => {
  // Check for user status
});

Auth 方法getRedirectResult的更新處理

模塊化 API 在getRedirectResult中引入了重大更改。當未調用重定向操作時,模塊化 API 將返回null ,這與命名空間 API 不同,命名空間 API 返回帶有null用戶的UserCredential

之前:兼容

const result = await auth.getRedirectResult()
if (result.user === null && result.credential === null) {
  return null;
}
return result;

之後:模塊化

const result = await getRedirectResult(auth);
// Provider of the access token could be Facebook, Github, etc.
if (result === null || provider.credentialFromResult(result) === null) {
  return null;
}
return result;

示例 2:重構 Cloud Firestore 函數

之前:兼容

import "firebase/compat/firestore"

const db = firebase.firestore();
db.collection("cities").where("capital", "==", true)
    .get()
    .then((querySnapshot) => {
        querySnapshot.forEach((doc) => {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch((error) => {
        console.log("Error getting documents: ", error);
    });

之後:模塊化

getFirestore函數將firebaseApp作為其第一個參數,該參數是在前面的示例中從initializeApp返回的。請注意,在模塊化 API 中,形成查詢的代碼有很大不同;沒有鏈接,並且諸如querywhere之類的方法現在公開為自由函數。

import { getFirestore, collection, query, where, getDocs } from "firebase/firestore";

const db = getFirestore(firebaseApp);

const q = query(collection(db, "cities"), where("capital", "==", true));

const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
  // doc.data() is never undefined for query doc snapshots
  console.log(doc.id, " => ", doc.data());
});

更新對 Firestore DocumentSnapshot.exists引用

模塊化 API 引入了一項重大更改,其中屬性firestore.DocumentSnapshot.exists已更改為方法。功能本質上是相同的(測試文檔是否存在),但您必須重構代碼以使用較新的方法,如下所示:

之前:兼容

if (snapshot.exists) {
  console.log("the document exists");
}

之後:模塊化

if (snapshot.exists()) {
  console.log("the document exists");
}

示例 3:結合命名空間和模塊化代碼風格

在升級期間使用兼容庫允許您繼續使用命名空間代碼以及為模塊化 API 重構的代碼。這意味著您可以保留 Cloud Firestore 的現有命名空間代碼,同時將身份驗證或其他 Firebase SDK 代碼重構為模塊化樣式,並且仍然可以使用兩種代碼樣式成功編譯您的應用。對於 Cloud Firestore 等產品中的命名空間和模塊化 API 代碼也是如此;只要您導入 compat 包,新舊代碼風格就可以共存:

import firebase from 'firebase/compat/app';
import 'firebase/compat/firestore';
import { getDoc } from 'firebase/firestore'

const docRef = firebase.firestore().doc();
getDoc(docRef);

請記住,雖然您的應用程序可以編譯,但在從應用程序中完全刪除 compat 語句和代碼之前,您將無法獲得模塊化代碼的應用程序大小優勢。

更新初始化代碼

更新應用程序的初始化代碼以使用模塊化語法。在完成應用程序中的所有代碼重構更新此代碼非常重要;這是因為firebase.initializeApp()會初始化 compat 和模塊化 API 的全局狀態,而模塊化的initializeApp()函數僅初始化模塊化的狀態。

之前:兼容

import firebase from "firebase/compat/app"

firebase.initializeApp({ /* config */ });

之後:模塊化

import { initializeApp } from "firebase/app"

const firebaseApp = initializeApp({ /* config */ });

刪除兼容代碼

要實現模塊化 API 的大小優勢,您最終應該將所有調用轉換為上面所示的模塊化樣式,並從代碼中刪除所有import "firebase/compat/*語句。完成後,不應再有任何引用到firebase.*全局命名空間或命名空間 API 樣式中的任何其他代碼。

從窗口使用 compat 庫

模塊化 API 經過優化,可以與模塊而不是瀏覽器的window對像一起使用。該庫的早期版本允許使用window.firebase命名空間加載和管理 Firebase。不建議繼續這樣做,因為它不允許消除未使用的代碼。然而,JavaScript SDK 的兼容版本確實適用於那些window希望立即開始模塊化升級路徑的開發人員。

<script src="https://www.gstatic.com/firebasejs/10.3.1/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.3.1/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.3.1/firebase-auth-compat.js"></script>
<script>
   const firebaseApp = firebase.initializeApp({ /* Firebase config */ });
   const db = firebaseApp.firestore();
   const auth = firebaseApp.auth();
</script>

兼容性庫在底層使用模塊化代碼,並為其提供與命名空間 API 相同的 API;這意味著您可以參考命名空間 API 參考和命名空間代碼片段以了解詳細信息。不建議長期使用此方法,而是作為升級到完全模塊化庫的開始。

模塊化 SDK 的優點和局限性

完全模塊化的 SDK 與早期版本相比具有以下優勢:

  • 模塊化 SDK 可以顯著減小應用程序的大小。它採用現代 JavaScript 模塊格式,允許“tree shake”實踐,在這種實踐中,您只導入應用程序需要的工件。根據您的應用程序,使用模塊化 SDK 進行樹搖動可以比使用命名空間 API 構建的類似應用程序減少 80% 的千字節數。
  • 模塊化 SDK 將繼續受益於正在進行的功能開發,而命名空間 API 則不會。