“Firebase 错误:Firestore 已启动,无法再更改其设置。” 将 Firebase v9 与 Firestore 模拟器连接

Gui*_*ost 9 firebase vue.js firebase-tools nuxt.js google-cloud-firestore

我几周前已更新到 Firebase v9,在尝试将我的 Firebase 应用程序连接到 Firestore 模拟器时遇到问题。

firebase.js(我的 VueJS 插件,我在其中设置 Firebase):

import { initializeApp, getApps } from "firebase/app"
import { getAuth, connectAuthEmulator, onAuthStateChanged } from "firebase/auth";
import { getFirestore, connectFirestoreEmulator } from "firebase/firestore"
import { getStorage, connectStorageEmulator } from "firebase/storage";
import { getFunctions, connectFunctionsEmulator } from 'firebase/functions';
import { isSupported, getAnalytics } from "firebase/analytics";

export default async ({ app }, inject) => {

  const firebaseConfig = {
    apiKey: process.env.FIREBASE_API_KEY,
    authDomain: process.env.FIREBASE_AUTH_DOMAIN,
    databaseURL: process.env.FIREBASE_DATABASE_URL,
    projectId: process.env.FIREBASE_PROJECT_ID,
    storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
    messagingSenderId: process.env.FIREBASE_MESSAGING_SERVICE_ID,
    appId: process.env.FIREBASE_APP_ID,
    measurementId: process.env.FIREBASE_MEASUREMENT_ID,
  }
  // I've checked, the values of firebaseConfig are all set here.

  // This IF statement is here to avoid initializing the app several times
  const apps = getApps();
  let firebaseApp = null;
  if (!apps.length) {
    firebaseApp = initializeApp(firebaseConfig);
  }
  else {
    firebaseApp = apps[0];
  }

  // INIT AUTH
  const auth = getAuth();
  auth.languageCode = 'fr';
  onAuthStateChanged(auth, async authUser => {
    const claims = authUser ? (await authUser.getIdTokenResult(true)).claims : null;
    await app.store.dispatch('onAuthStateChanged', { authUser, claims });
  },
  (error) => {
    console.error("Firebase Auth onAuthStateChanged ERROR", error)
  });
  
  // Get other services
  const firestore = getFirestore(firebaseApp);
  const storage = getStorage(firebaseApp);
  const functions = getFunctions(firebaseApp, process.env.FIREBASE_REGION);

  // Setup analytics if supported
  let analytics = null;
  const analyticsSupported = await isSupported()
  if (analyticsSupported) {
    analytics = getAnalytics();
    analytics.automaticDataCollectionEnabled = false;
  }

  // Connecting to emulators
  if (process.client && process.env.APP_ENV === 'local') {
    console.log("LOCAL ENVIRONMENT, CONNECTING TO EMULATORS...");
    connectAuthEmulator(auth, "http://localhost:9099");
    connectFirestoreEmulator(firestore, 'localhost', 8080);
    connectStorageEmulator(storage, "localhost", 9199);
    connectFunctionsEmulator(functions, "localhost", 5001);
  }

  Inject firebase objects into my VueJS app
  const fire = { auth, firestore, storage, functions, analytics }
  inject('fire', fire);
}
Run Code Online (Sandbox Code Playgroud)

这是我得到的错误,由这一行引起:connectFirestoreEmulator(firestore, 'localhost', 8080);

在此输入图像描述

FirebaseError Firestore 已启动,无法再更改其设置。您只能在调用 Firestore 对象上的任何其他方法之前修改设置。

我不想settings自己修改 Firestore 对象的属性,所以它必须是 method connectFirestoreEmulator

问题可以缩小到以下代码:

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

export default async ({ app }, inject) => {

  const firebaseConfig = {
    apiKey: process.env.FIREBASE_API_KEY,
    authDomain: process.env.FIREBASE_AUTH_DOMAIN,
    databaseURL: process.env.FIREBASE_DATABASE_URL,
    projectId: process.env.FIREBASE_PROJECT_ID,
    storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
    messagingSenderId: process.env.FIREBASE_MESSAGING_SERVICE_ID,
    appId: process.env.FIREBASE_APP_ID,
    measurementId: process.env.FIREBASE_MEASUREMENT_ID,
  }

  firebaseApp = initializeApp(firebaseConfig);
  const firestore = getFirestore(firebaseApp);
  if (process.env.APP_ENV === 'local') {
    connectFirestoreEmulator(firestore, 'localhost', 8080);
  }

  const fire = { auth, firestore, storage, functions, analytics };
  inject('fire', fire);
}
Run Code Online (Sandbox Code Playgroud)

我设法通过添加来避免触发错误process.client,因此它不会连接到服务器端(SSR)上的模拟器:

  if (process.client && process.env.APP_ENV === 'local') {
Run Code Online (Sandbox Code Playgroud)

然而,当我添加这一点时,当在第一页加载时在服务器端(SSR)执行代码时,模拟器不会连接,并且初始 Firestore 数据是从真正的 Firebase 应用程序而不是模拟器中读取的。

知道如何管理 SSR 上与 Firestore 模拟器的正确连接吗?

这是 Firebase 错误吗?

我使用的版本:

  • 在我的应用程序中:Firebase JS SDK v9.6.9
  • 模拟器:模拟器的 firebase-tools v10.4.0

我已经读过/尝试过的内容:

小智 8

已经有一段时间了,但我遇到了类似的问题,经过一番折腾后,我最终找到了一个解决方案(尽管感觉有点老套)。

在运行 connectFirestoreEmulator 行之前,检查 firestor._settingsFrozen 是否为 false。因此,基本上只有在 Firestore 尚未初始化时才运行该行。您可以通过在 connectFirestoreEmulator 行之前注销 firestore 变量并查看其中的设置内容来检查 firestore 是否已使用模拟器设置进行初始化 - 如果它显示端口是 8080 并且主机是 localhost,那么就可以了。

这是我的比较代码(与您的设置略有不同,但我相信我们遇到了同样的问题):

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

const firebaseConfig = {
  apiKey: "XXXXXXXXX",
  authDomain: "XXXXXXXXX",
  projectId: "XXXXXXXXX",
  storageBucket: "XXXXXXXXX",
  messagingSenderId: "XXXXXXXXX",
  appId: "XXXXXXXXX",
  measurementId: "XXXXXXXXX",
};

const app = initializeApp(firebaseConfig);

export const auth = getAuth(app);
export const db = getFirestore(app);

export default (context) => {
  if (context.env.appEnv === 'dev') {
    connectAuthEmulator(auth, `http://127.0.0.1:${context.env.authPort}`);

    if (!db._settingsFrozen) {
      connectFirestoreEmulator(db, '127.0.0.1', parseInt(context.env.firestorePort));
    }
  }
}
Run Code Online (Sandbox Code Playgroud)


Jos*_*hez 0

查看Firebase JS SDK相关问题,该问题似乎是因为 Firestore 实例(如下初始化:)firestore = getFirestore(firebaseApp)是在模拟器(connectFirestoreEmulator)启动后调用的。

调用"connectFirestoreEmulator"方法后,"firestore"变量正在常量变量中使用"fire = { auth, firestore, storage, functions, analytics }"

如果在连接模拟器之前使用“const fire”,问题可能会得到解决。

这是一个可能对您有帮助的代码示例:

firebaseApp = initializeApp(firebaseConfig);

 const fire = { auth, firestore, storage, functions, analytics };

  const firestore = getFirestore(firebaseApp);
  if (process.env.APP_ENV === 'local') {
    connectFirestoreEmulator(firestore, 'localhost', 8080);
  }
Run Code Online (Sandbox Code Playgroud)

作为参考,我使用了这个github 存储库