【问题标题】:"Firebase Error : Firestore has already been started and its settings can no longer be changed." connecting Firebase v9 with Firestore Emulator\“Firebase 错误:Firestore 已经启动,无法再更改其设置。\”将 Firebase v9 与 Firestore 模拟器连接
【发布时间】:2022-12-08 06:44:26
【问题描述】:

几周前我已经更新到 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);
}

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

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

我不想自己修改 Firestore 对象的 settings 属性,所以它必须是方法 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);
}

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

  if (process.client && process.env.APP_ENV === 'local') {

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

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

这是一个 Firebase 错误吗?

我使用的版本:

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

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

【问题讨论】:

  • 嗨 Guillaume,我编辑了 Firebase JS SDK 的答案
  • 我在使用 Next.js 和 Firebase 模拟器时偶然发现了同样的问题。将其缩小到导致问题的 connectFirestoreEmulator 函数。很确定这是一个错误。您找到解决方法了吗?

标签: firebase vue.js google-cloud-firestore nuxt.js firebase-tools


【解决方案1】:

审阅Firebase 开发工具包问题相关,似乎问题是因为在模拟器(connectFirestoreEmulator) 启动后调用了 Firestore 实例(像这样初始化:firestore = getFirestore(firebaseApp))。

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

如果在连接到模拟器之前使用“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);
  }

作为参考,我使用了这个github repository

【讨论】:

  • 感谢你的回复 !我说的是 Firebase JS SDK 而不是 Firebase Admin,它们有点不同。
  • 感谢您的更新,但不幸的是,这个解决方案没有奏效(我试过只是为了确定,但仍然出现错误)。我不认为 const fire = ... 的分配是负责任的:它似乎来自对 connectFirestoreEmulator 的调用内部发生的事情:每当在服务器端调用它时,我都会收到错误。问题仍然没有解决:(
【解决方案2】:

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

在运行 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));
    }
  }
}

【讨论】:

    猜你喜欢
    • 2020-09-05
    • 2020-06-17
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-19
    • 1970-01-01
    相关资源
    最近更新 更多