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

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

本指南假定您熟悉命名空間 API,並且您將利用模塊捆綁器(例如webpackRollup)進行升級和持續的模塊化應用程序開發。

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

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

關於命名空間 ( compat ) 庫

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

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

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

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

關於升級過程

升級過程的每一步都有範圍限制,這樣您就可以完成對應用程序源代碼的編輯,然後編譯並運行它而不會中斷。總而言之,以下是您升級應用程序時需要執行的操作:

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

獲取最新版本的SDK

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

npm i firebase@9.22.1

# OR

yarn add firebase@9.22.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 中,服務作為第一個參數傳遞,然後函數使用服務的詳細信息來完成其餘的工作。讓我們在重構對 Authentication API 和 Cloud Firestore API 的調用的兩個示例中檢查它是如何工作的。

示例 1:重構身份驗證函數

之前:兼容

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

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 則返回帶有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已更改為方法。功能基本相同(測試文檔是否存在),但您必須重構代碼以使用 v9 方法,如下所示:

之前:兼容

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 代碼也是如此;新舊代碼風格可以共存,只要你導入兼容包:

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()為兼容 API 和模塊化 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 樣式中的任何其他代碼。

從窗口使用兼容庫

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

<script src="https://www.gstatic.com/firebasejs/9.22.1/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.22.1/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.22.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 模塊格式,允許您僅導入應用程序需要的工件的“搖樹”實踐。根據您的應用程序,與使用命名空間 API 構建的同類應用程序相比,使用模塊化 SDK 進行 tree-shaking 可以減少 80% 的千字節數。
  • 模塊化 SDK 將繼續受益於正在進行的功能開發,而命名空間 API 則不會。