当前使用 Firebase Web SDK 版本 8 或更早版本的应用应考虑按照本指南中的说明迁移到版本 9。
本指南假定您熟悉版本 8,并且您将利用模块捆绑器(例如webpack或Rollup )来升级和进行版本 9 开发。
强烈建议在您的开发环境中使用模块捆绑器。如果您不使用其中之一,您将无法利用版本 9 在减小应用程序大小方面的主要优势。您需要npm或yarn来安装 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 模块化”的说明进行操作,而无需使用兼容库。
关于升级过程
升级过程的每个步骤都有范围,以便您可以完成对应用程序源代码的编辑,然后编译并运行它而不会损坏。总而言之,升级应用程序需要执行以下操作:
- 将版本 9 库和兼容库添加到您的应用程序。
- 将代码中的 import 语句更新为 v9 compat。
- 将单个产品(例如身份验证)的代码重构为模块化样式。
- 可选:此时,移除 Authentication 兼容库和 Authentication 兼容代码,以便在继续之前实现 Authentication 的应用程序大小优势。
- 将每个产品(例如 Cloud Firestore、FCM 等)的功能重构为模块化样式,编译和测试,直到所有区域完成。
- 将初始化代码更新为模块化样式。
- 从您的应用程序中删除所有剩余的版本 9 兼容语句和兼容代码。
获取版本 9 SDK
首先,使用 npm 获取版本 9 库和兼容库:
npm i firebase@9.15.0 # OR yarn add firebase@9.15.0
将导入更新为 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 中有很大的不同;没有链接, query
或where
等方法现在作为自由函数公开。
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.15.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.15.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.15.0/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 版将在未来某个时间点冻结。