Firebase 模拟器设置:getFirestore() 或 getFirestore(firebaseApp)?

Firebase emulator setup: getFirestore() or getFirestore(firebaseApp)?

在研究如何将您的应用程序连接到 Firebase 模拟器(例如 Firestore 模拟器)时,我发现主要 documentation 说明我们会这样做(Web 版本 9):

import { getFirestore, connectFirestoreEmulator } from "firebase/firestore";

// firebaseApps previously initialized using initializeApp()
const db = getFirestore(); // <-- Notice they don't pass-in firebaseApp here
connectFirestoreEmulator(db, 'localhost', 8080); 

我也见过这样的 getFirestore() 调用:

import { initializeApp } from 'firebase/app';
import { getFirestore, connectFirestoreEmulator } from 'firebase/firestore';

const config = { /* Firebase project config here  */ };
const firebaseApp = initializeApp(config);
const db = getFirestore(firebaseApp); // <-- Notice firebaseApp passed-in
connectFirestoreEmulator(db, 'localhost', 8080);

getFirestore() 的 Firestore API 文档指出:

"Returns the existing Firestore instance that is associated with the provided FirebaseApp. If no instance exists, initializes a new instance with default settings."

根据该描述,我对在调用 getFirestore() 时是否传入初始化的 firebaseApp 感到困惑。我有多个 Firebase 服务,我想模拟(并相互交谈)所以我认为我 应该 传递我的 firebaseApp.

哪个是正确的?是否有需要注意的“陷阱”?

我仔细查看了源代码以了解到底发生了什么,这是我发现的:

getFirestore方法的代码如下:

/**
 * Returns the existing {@link Firestore} instance that is associated with the
 * provided {@link @firebase/app#FirebaseApp}. If no instance exists, initializes a new
 * instance with default settings.
 *
 * @param app - The {@link @firebase/app#FirebaseApp} instance that the returned {@link Firestore}
 * instance is associated with.
 * @returns The {@link Firestore} instance of the provided app.
 */
function getFirestore(app = app.getApp()) {
    return app._getProvider(app, 'firestore').getImmediate();
}

如果您不将应用程序实例传递给该函数,那么它会将 app 变量设置为 app.getApp()

在代码的前面,app 被定义为 require("@firebase/app"),因此我们需要查看该包中的 getApp 方法。

getApp 方法声明为as-follows:

/**
 * Retrieves a {@link @firebase/app#FirebaseApp} instance.
 *
 * When called with no arguments, the default app is returned. When an app name
 * is provided, the app corresponding to that name is returned.
 *
 * An exception is thrown if the app being retrieved has not yet been
 * initialized.
 *
 * @example
 * ```javascript
 * // Return the default app
 * const app = getApp();
 * ```
 *
 * @example
 * ```javascript
 * // Return a named app
 * const otherApp = getApp("otherApp");
 * ```
 *
 * @param name - Optional name of the app to return. If no name is
 *   provided, the default is `"[DEFAULT]"`.
 *
 * @returns The app corresponding to the provided app name.
 *   If no app name is provided, the default app is returned.
 *
 * @public
 */
export declare function getApp(name?: string): FirebaseApp;

这告诉我们,当您初始化一个 firebase 应用程序时,它会使用一个标识该实例的名称进行初始化。

initializeApp方法声明如下:

/**
 * Creates and initializes a {@link @firebase/app#FirebaseApp} instance.
 *
 * See
 * {@link
 *   https://firebase.google.com/docs/web/setup#add_firebase_to_your_app
 *   | Add Firebase to your app} and
 * {@link
 *   https://firebase.google.com/docs/web/setup#multiple-projects
 *   | Initialize multiple projects} for detailed documentation.
 *
 * @example
 * ```javascript
 *
 * // Initialize default app
 * // Retrieve your own options values by adding a web app on
 * // https://console.firebase.google.com
 * initializeApp({
 *   apiKey: "AIza....",                             // Auth / General Use
 *   authDomain: "YOUR_APP.firebaseapp.com",         // Auth with popup/redirect
 *   databaseURL: "https://YOUR_APP.firebaseio.com", // Realtime Database
 *   storageBucket: "YOUR_APP.appspot.com",          // Storage
 *   messagingSenderId: "123456789"                  // Cloud Messaging
 * });
 * ```
 *
 * @example
 * ```javascript
 *
 * // Initialize another app
 * const otherApp = initializeApp({
 *   databaseURL: "https://<OTHER_DATABASE_NAME>.firebaseio.com",
 *   storageBucket: "<OTHER_STORAGE_BUCKET>.appspot.com"
 * }, "otherApp");
 * ```
 *
 * @param options - Options to configure the app's services.
 * @param name - Optional name of the app to initialize. If no name
 *   is provided, the default is `"[DEFAULT]"`.
 *
 * @returns The initialized app.
 *
 * @public
 */
export declare function initializeApp(options: FirebaseOptions, name?: string): FirebaseApp;

这告诉我们,如果您在调用 initializeApp 时没有提供实例名称作为第二个参数,那么将使用名称 "[DEFAULT]"

生成实例

最终这意味着除非您手动命名您的 firebase 应用程序实例,否则您不需要在调用 getFirestore 时传入它。它将能够获取您的单个主要应用程序实例并在必要时使用它。

手动 v.s 将应用程序实例传递给 getFirestore 应该没有任何区别。让Firestore直接通过firebase/app

获取实例

如果您只需要使用一个 Firebase 应用程序,您可以执行其中任何一个,但如果您有多个应用程序,则需要初始化每个应用程序,为其提供配置并获取其特定的 firestore。

import { getFirestore, connectFirestoreEmulator } from "firebase/firestore";

const db = getFirestore();
connectFirestoreEmulator(db, 'localhost', 8080); 

仅当您的上下文中有一个已初始化的 firebase 应用程序并且只有一个时才有效。

如果您希望拥有多个 firebase 应用程序,您需要初始化每个应用程序并指定您要访问的 firestore。

通过

import { initializeApp } from 'firebase/app';
import { getFirestore, connectFirestoreEmulator } from 'firebase/firestore';

const config = { /* Firebase project config here  */ };
const firebaseApp = initializeApp(config);
const db = getFirestore(firebaseApp);
connectFirestoreEmulator(db, 'localhost', 8080);