Firebase Firestore 模拟器错误`已在 settings() 和 useEmulator() 中设置了主机,将使用模拟器主机`

Mos*_*ham 5 firebase reactjs next.js google-cloud-firestore firebase-cli

首先,这是我得到的完整错误。

@firebase/firestore:Firestore (8.1.1):在 settings() 和 useEmulator() 中都设置了主机,将使用模拟器主机
错误 [FirebaseError]:Firestore 已经启动,无法再更改其设置。您只能在调用 Firestore 对象上的任何其他方法之前修改设置。

这就是我初始化模拟器的方式

const db = app.firestore();
const auth = firebase.auth();
if (process.env.NODE_ENV === 'development') {
  db.useEmulator('localhost', 8888);
  firebase.auth().useEmulator('http://localhost:9099/');
}
Run Code Online (Sandbox Code Playgroud)

当我第一次启动应用程序时,项目正在运行 nextjs 一切都按预期运行,但是在 next.js 页面之间刷新或导航后,我突然收到此错误。我必须杀死终端并重新开始,这很烦人我不知道 next.js 服务器是否多次运行if (process.env.NODE_ENV === 'development')代码,这可能是导致此错误的原因,如果是这种情况下如何避免在那里设置新模拟器已经是一个了。还是与 firebase 模拟器相关的错误?

Mos*_*ham 13

after trying almost all of the solutions here it didn't really work the bug was happening from time to time the annoying thing is that I didn't know how to reproduce it but I think it happens when this page has a server-side error anyway the solution I used for getting around this bug was the following

const EMULATORS_STARTED = 'EMULATORS_STARTED';
function startEmulators() {
  if (!global[EMULATORS_STARTED]) {
    global[EMULATORS_STARTED] = true;
    firebase.firestore().useEmulator('localhost', 8888);
    firebase.auth().useEmulator('http://localhost:9099/');
  }
}

if (process.env.NODE_ENV === 'development') {
  startEmulators();
}
Run Code Online (Sandbox Code Playgroud)

but for this to work like expected you will need to make sure that all emulators have started before making a request to the next.js server because if this code was executed before the emulators start then global[EMULATORS_STARTED] would be true and it will never use the emulators in this case. I have tested this on so many pages and some of them had server-side errors and the bug wasn't happening instead I got logs of these errors which is the expected behavior I didn't know these Errors existed in the first place before applying this solution .


Rea*_*lar 6

NextJs 正在热重新加载网页,并且为同一浏览器xxx.useEmulator(...)实例调用两次。

在底层,Firebase 库使用对当前应用程序的全局引用,从库的角度来看,您尝试对其进行两次或更多次初始化。

您可以使用以下代码重现此问题:

const db = app.firestore();
db.useEmulator('localhost', 8888);
db.useEmulator('localhost', 8888); // raises error
Run Code Online (Sandbox Code Playgroud)

我发现的唯一解决方法是使用窗口对象来保存一个标志(无论它是否已初始化),但您还必须处理 SSR 的边缘情况。

const db = app.firestore();
if(typeof window === 'undefined' || !window['_init']) {
   db.useEmulator('localhost', 8888);
   if(typeof window !== 'undefined') {
      window['_init'] = true;
   }
}
Run Code Online (Sandbox Code Playgroud)

这不是上面最优雅的代码,但它修复了错误。

关键是要知道热重载是问题所在,Firebase 应该只配置一次。