從命名空間 API 升級至模組 API

如果應用程式目前使用任何命名空間 Firebase Web API,從 compat 程式庫回溯至 8 以下版本,應考慮按照本指南的操作說明,改用模組化 API。

本指南假設您熟悉命名空間 API,且利用 webpackRollup 等模組整合工具,進行升級和後續的模組化應用程式開發作業。

強烈建議您在開發環境中使用模組組合器。如果不使用,就無法享有模組 API 的主要優勢,無法縮減應用程式大小。您需要使用 npmyarn 才能安裝 SDK。

本指南中的升級步驟將以使用驗證和 Cloud Firestore SDK 的虛構網頁應用程式為基礎。透過這些範例,您可以掌握升級所有支援的 Firebase Web SDK 所需的概念和實際步驟。

關於命名空間 (compat) 程式庫

Firebase Web SDK 有兩種程式庫類型:

  • 模組化 - 這個新 API 介面專為協助樹動 (移除未使用的程式碼) 而設計,讓網頁應用程式盡可能縮小且快速。
  • 命名空間 (compat):這個熟悉的 API 介面與舊版 SDK 完全相容,因此您不必一次變更所有 Firebase 程式碼,就能升級帳戶。比起命名空間,Compat 程式庫幾乎沒有大小或效能方面的優勢。

本指南假設您利用相容性程式庫加速升級。這些程式庫可讓您繼續使用命名空間程式碼,以及重構模組化 API 的程式碼。也就是說,在升級程序期間,您可以更輕鬆地編譯及偵錯應用程式。

如果應用程式幾乎不會使用 Firebase Web SDK (例如只呼叫 Authentication API 的應用程式),很適合在不使用 Compat 程式庫的情況下重構較舊的命名空間程式碼。如果您要升級這類應用程式,則無需使用相容程式庫,即可按照「模組化 API」指南中的指示操作。

關於升級程序

升級程序的每個步驟都設有範圍,因此您可以完成應用程式來源編輯作業,並在不中斷的情況下編譯及執行。總結來說,升級應用程式的步驟如下:

  1. 將模組化程式庫和 Compat 程式庫新增至應用程式。
  2. 更新程式碼中的匯入陳述式,以便遵守規範。
  3. 將單一產品 (例如驗證) 的程式碼重構為模組樣式。
  4. 選用:此時,請移除驗證相容性程式庫和驗證的相容性程式碼,以便在繼續操作之前,先充分瞭解應用程式大小對驗證的好處。
  5. 將各項產品 (例如 Cloud Firestore、FCM 等) 的函式重構為模組樣式,並進行編譯和測試,直到所有區域都完成。
  6. 將初始化程式碼更新為模組樣式。
  7. 從應用程式中移除所有剩餘的 Compat 陳述式和 Compat 程式碼。

取得最新版 SDK

如要開始使用,請使用 npm 取得模組化程式庫和 Compat 程式庫:

npm i firebase@10.12.2

# OR

yarn add firebase@10.12.2

將匯入項目更新為相容版本

為了讓程式碼在更新依附元件後保持運作,請變更匯入陳述式,以使用每個匯入的「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:重構驗證函式

變更前:相容性

Compat 程式碼與命名空間程式碼相同,但匯入作業已變更。

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

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

變更後:模組化

getAuth 函式使用 firebaseApp 做為第一個參數。onAuthStateChanged 函式不會與 auth 執行個體鏈結在一起,就像在命名空間 API 中一樣;而是免費函式,使用 auth 做為第一個參數。

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

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

更新驗證方法「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 已變更為方法。基本上,功能相同 (測試文件是否存在),但您必須重構程式碼才能使用較新的方法,如下所示:

Before:compat

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

變更後:模組化

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

範例 3:結合命名空間和模組化程式碼樣式

在升級期間使用 Compat 程式庫可讓您繼續使用命名空間程式碼,以及為模組化 API 重構的程式碼。這表示在將驗證或其他 Firebase SDK 程式碼重構為模組樣式時,您可以保留 Cloud Firestore 現有的命名空間程式碼,且仍可使用這兩種程式碼樣式成功編譯應用程式。對 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);

請注意,雖然您的應用程式會編譯,但您必須從應用程式完全移除相容性陳述式和程式碼,才能享有模組程式碼的優點。

更新初始化程式碼

如要使用模組語法,請更新應用程式的初始化程式碼。請務必在應用程式完成所有程式碼的重構「之後」更新這段程式碼,這是因為 firebase.initializeApp() 會同時初始化相容 API 和模組化 API 的全域狀態,而模組型 initializeApp() 函式只會初始化模組化的狀態。

變更前:相容性

import firebase from "firebase/compat/app"

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

變更後:模組化

import { initializeApp } from "firebase/app"

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

移除 Compat 程式碼

為了實現模組 API 的大小優勢,您最終應該將所有叫用轉換為上方所示的模組化樣式,並移除程式碼中的所有 import "firebase/compat/* 陳述式。完成後,您就不能再參照 firebase.* 全域命名空間或任何命名空間 API 樣式中的任何其他程式碼。

從視窗中使用 Compat 程式庫

模組化 API 經過最佳化調整,適用於模組,而非瀏覽器的 window 物件。先前的程式庫版本允許使用 window.firebase 命名空間載入及管理 Firebase。這種做法不允許刪除未使用的程式碼,因此不建議日後執行這項操作。不過,對於不想立即展開模組化升級路徑的開發人員,JavaScript SDK 相容性版本可與 window 搭配使用。

<script src="https://www.gstatic.com/firebasejs/10.12.2/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.12.2/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.12.2/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 模組格式,可讓您只匯入應用程式所需的構件,藉此執行「樹動搖動」做法。視應用程式而定,透過模組化 SDK 進行樹狀結構時,與使用命名空間 API 建構的類似應用程式相比,可以減少 80% 的 KB 數。
  • 模組化 SDK 將繼續受益於持續開發的功能,但命名空間 API 則無法。