從命名空間 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.9.0

# OR

yarn add firebase@10.9.0

更新導入以相容

為了在更新依賴項後保持程式碼正常運行,請變更導入語句以使用每個導入的“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.9.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.9.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.9.0/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 則不會。