從命名空間 API 升級至模組化應用程式

使用任何命名空間 Firebase Web API 的應用程式 (從 compat 程式庫到 8 以下版本),應考慮按照本指南中的操作說明,遷移至模組化 API。

本指南假設您熟悉命名空間 API,且會利用 webpackRollup 等模組整合工具,升級及持續開發模組化應用程式。

強烈建議您在開發環境中使用模組套件組合器。如果您沒有使用模組化 API,就無法享有其主要的優點,也就是縮減應用程式大小。您需要使用 npmyarn 安裝 SDK。

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

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

Firebase Web SDK 提供兩種程式庫:

  • 模組化:新的 API 介面,旨在協助樹狀圖搖動 (移除未使用的程式碼),讓您的網頁應用程式盡可能小且快速。
  • 命名空間 (compat):這是一個熟悉的 API 介面,可與 SDK 的舊版完全相容,讓您升級時不必一次變更所有 Firebase 程式碼。相較於命名空間對應程式庫,相容性程式庫的大小或效能優勢幾乎不存在。

本指南假設您會善用 Compat 程式庫來簡化升級程序。這些程式庫可讓您繼續使用命名空間程式碼,以及為模組化 API 重構的程式碼。這表示您在升級過程中,可以更輕鬆地編譯及偵錯應用程式。

如果應用程式只會稍微使用 Firebase Web SDK (例如,只會對 Authentication API 進行簡單呼叫),不使用相容性程式庫,可能會更實際地重構較舊的命名空間程式碼。如果您要升級這類應用程式,可以按照本指南的「模組 API」操作說明操作,而無須使用相容性程式庫。

關於升級程序

升級程序的每個步驟都會設有範圍,讓您可以完成應用程式來源的編輯作業,然後編譯並執行應用程式,而不會造成損壞。總結來說,您需要採取下列步驟升級應用程式:

  1. 將模組化程式庫和相容性程式庫新增至應用程式。
  2. 更新程式碼中的匯入陳述式,以便相容。
  3. 將單一產品 (例如 Authentication) 的程式碼重構為模組化樣式。
  4. 選用:此時,請移除 Authentication 相容性程式庫和 Authentication 的相容性程式碼,以便在繼續之前實現 Authentication 的應用程式大小優勢。
  5. 將每個產品的函式 (例如 Cloud FirestoreFCM 等) 重構為模組化樣式,並編譯及測試,直到所有區域都完成為止。
  6. 將初始化程式碼更新為模組化樣式。
  7. 從應用程式中移除所有剩餘的相容性陳述式和相容性程式碼。

取得最新版 SDK

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

npm i firebase@11.3.0

# OR

yarn add firebase@11.3.0

將匯入內容更新為相容

為了讓程式碼在更新依附元件後仍能正常運作,請將匯入陳述式變更為使用每個匯入項目的「相容性」版本。例如:

舊版:8 以下版本

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

變更後:compat

// 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 中,服務會做為第一個引數傳遞,然後函式會使用服務的詳細資料執行其餘的作業。讓我們透過兩個重構 AuthenticationCloud Firestore API 呼叫的範例,瞭解這項功能的運作方式。

範例 1:重構 Authentication 函式

變更前: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

變更前:compat

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

變更前:compat

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

變更前:compat

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

變更後:模組化

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

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

在升級期間使用相容性程式庫,可讓您繼續使用命名空間程式碼,以及為模組化 API 重構的程式碼。也就是說,您可以保留 Cloud Firestore 的現有命名空間程式碼,同時將 Authentication 或其他 Firebase SDK 程式碼重構為模組化樣式,並且仍可使用這兩種程式碼樣式成功編譯應用程式。同樣地,如果產品有命名空間和模組化 API 程式碼,例如 Cloud Firestore,新舊程式碼樣式也能共存,只要您匯入相容性套件即可:

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 初始化全域狀態,而模組化 initializeApp() 函式只會為模組化初始化狀態。

變更前:compat

import firebase from "firebase/compat/app"

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

變更後:模組化

import { initializeApp } from "firebase/app"

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

移除相容性程式碼

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

使用視窗中的相容性程式庫

模組化 API 經過最佳化,可搭配模組而非瀏覽器的 window 物件運作。舊版程式庫可透過 window.firebase 命名空間載入及管理 Firebase。但我們不建議您採用這種做法,因為系統無法刪除未使用的程式碼。不過,如果開發人員不想立即開始模組化升級程序,JavaScript SDK 的相容版本仍可與 window 搭配運作。

<script src="https://www.gstatic.com/firebasejs/11.3.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/11.3.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/11.3.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 模組格式,可執行「樹狀圖搖動」做法,只匯入應用程式需要的構件。根據應用程式,使用模組化 SDK 進行樹狀圖搖晃,可比使用命名空間 API 建構的類似應用程式,減少 80% 的千位元。
  • 模組化 SDK 會持續從持續的功能開發中受益,而命名空間 API 則不會。