從版本 8 升級到模塊化 Web SDK

當前使用 Firebase Web SDK 版本 8 或更早版本的應用應考慮按照本指南中的說明遷移到版本 9。

本指南假定您熟悉版本 8,並且您將利用模塊捆綁器(例如webpackRollup )來升級和進行版本 9 開發。

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

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

關於兼容庫

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

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

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

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

關於升級過程

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

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

獲取版本 9 SDK

首先,使用 npm 獲取版本 9 庫和兼容庫:

npm i firebase@9.17.2

# OR

yarn add firebase@9.17.2

將導入更新為 v9 兼容

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

之前:版本 8

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

之後:版本 9 兼容

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

重構為模塊化風格

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

在版本 9 中,服務作為第一個參數傳遞,然後該函數使用服務的詳細信息來完成其餘的工作。讓我們在兩個重構對身份驗證和 Cloud Firestore API 調用的示例中檢查其工作原理。

示例 1:重構 Authentication 函數

之前:版本 9 兼容

版本 9 兼容代碼與版本 8 代碼相同,但導入已更改。

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

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

之後:版本 9 模塊化

getAuth函數將firebaseApp作為其第一個參數。 onAuthStateChanged函數不像在版本 8 中那樣與auth實例鏈接;相反,它是一個以auth作為其第一個參數的自由函數。

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

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

更新 Auth 方法getRedirectResult的處理

版本 9 在getRedirectResult中引入了一項重大更改。當沒有調用重定向操作時,版本 9 返回null ,而版本 8 返回帶有null用戶的UserCredential

之前:版本 9 兼容

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

之後:版本 9 模塊化

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 函數

之前:版本 9 兼容

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

之後:版本 9 模塊化

getFirestore函數將firebaseApp作為其第一個參數,該參數在前面的示例中從initializeApp返回。注意形成查詢的代碼在版本 9 中有很大的不同;沒有鏈接, 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的引用

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

之前:版本 9 兼容

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

之後:版本 9 模塊化

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

示例 3:結合版本 8 和版本 9 代碼樣式

在升級期間使用兼容庫允許您繼續使用版本 8 代碼以及為版本 9 重構的代碼。這意味著您可以保留 Cloud Firestore 的現有版本 8 代碼,同時將身份驗證或其他 Firebase SDK 代碼重構為版本 9 樣式,並且仍然使用兩種代碼樣式成功編譯您的應用程序。 Cloud Firestore 等產品的版本 8 和版本 9 代碼也是如此;新舊代碼樣式可以共存,只要您導入兼容包即可:

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

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

請記住,儘管您的應用程序可以編譯,但在您從應用程序中完全刪除兼容語句和代碼之前,您不會獲得模塊化代碼的應用程序大小優勢。

更新初始化代碼

更新應用的初始化代碼以使用新的模塊化版本 9 語法。完成應用程序中所有代碼的重構更新此代碼很重要;這是因為firebase.initializeApp()初始化了兼容 API 和模塊化 API 的全局狀態,而模塊化的initializeApp()函數只初始化了模塊化的狀態。

之前:版本 9 兼容

import firebase from "firebase/compat/app"

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

之後:版本 9 模塊化

import { initializeApp } from "firebase/app"

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

刪除兼容代碼

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

從窗口使用兼容庫

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

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

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

版本 9 的優點和限制

與早期版本相比,完全模塊化的版本 9 具有以下優點:

  • 版本 9 可顯著減小應用程序大小。它採用現代 JavaScript 模塊格式,允許“搖樹”實踐,在這種實踐中,您只導入應用所需的工件。根據您的應用程序,使用版本 9 的 tree-shaking 可以比使用版本 8 構建的同類應用程序減少 80% 的千字節。
  • 第 9 版將繼續受益於正在進行的功能開發,而第 8 版將在未來某個時間點凍結。