Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase Firestore emulator error `Host has been set in both settings() and useEmulator(), emulator host will be used`

first of all that is the full error I got.

@firebase/firestore: Firestore (8.1.1): Host has been set in both settings() and useEmulator(), emulator host will be used
Error [FirebaseError]: Firestore has already been started and its settings can no longer be changed. You can only modify settings before calling any other methods on a Firestore object.

this is how I init the emulator

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

the project is running nextjs when I first start the application everything run as expected but after some refreshing or navigation among next.js pages, I suddenly get this error. and I have to kill the terminal and start over which is annoying I don't know if next.js server runs the if (process.env.NODE_ENV === 'development') code several times and this could be the cause of this error if that is case how to avoid setting a new emulator when there is one already. or is it a bug related to firebase emulators?.

like image 522
Mostafa Hesham Avatar asked Nov 30 '20 01:11

Mostafa Hesham


People also ask

How do I turn off firebase emulator?

Double tap CTRL-C (hold down CTRL and double tap C) in the terminal running the emulator when you want to shut down the emulator and clear all the ports and processes.

Is not open on localhost could not start firestore emulator?

This error is because of the failed quitting from firebase emulator. You already have the process of previous firebase emulator. For a new start, you have to find and stop the previous process.

How do I use firestore emulator in react?

Inside the root of your react app directory, enable Firestore by running $ firebase init firestore --project $fbid , which will error out with a link to enable the feature in the Firebase console. After doing so, re-run $ firebase init firestore --project $fbid , which will create a couple of files.


2 Answers

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();
}

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 😁.

like image 80
Mostafa Hesham Avatar answered Oct 11 '22 07:10

Mostafa Hesham


NextJs is hot-reloading the web page, and xxx.useEmulator(...) is being called twice for the same browser instance.

Under the hood the Firebase library uses a global reference to the current app, and from the perspective of the library you're trying to initialize it twice or more.

You can reproduce this problem with the following code:

const db = app.firestore();
db.useEmulator('localhost', 8888);
db.useEmulator('localhost', 8888); // raises error

The only work-around that I've found is to use the window object to hold a flag if it's been initialized or not, but you also have to handle the edge case of SSR.

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

It's not the most elegant code above but it fixes the error.

The key is to know that hot reloading is the problem, and Firebase should only be configured once.

like image 28
Reactgular Avatar answered Oct 11 '22 08:10

Reactgular