Closed Janque closed 1 year ago
@Janque - can you provide an example of how you're using RTDB with Next.js?
If I understand this correctly, the recommendation from @Janque is to modify the getDatabase(...)
function in RTDB to only attempt to connect to to the emulator if the RTDB instance has not started? That is, make RTDB behave the same as Firestore in initialization.
For general housekeeping, I'm going to remove the firestore tag from this issue.
@Janque - can you provide an example of how you're using RTDB with Next.js?
Well, as I said it's not really an issue with a specific use, but rather the initialization. Here is an simplified bit that also triggered the error:
// pages/index.js
import { incrementCount } from '../firebase/database';
export default function Home(props) {
//...
}
export async function getServerSideProps() {
await incrementCount();
return {props:{
//...
}}
}
// firebase/firebase.js
//...
export const firebaseApp = initializeApp(firebaseConfig);
export const database = getDatabase(firebaseApp);
//...
// firebase/database.js
import { database } from './firebase';
import { ref, set, increment } from "firebase/database";
export async function incrementCount() {
await set(ref(database, "count"), increment(1));
return;
}
After I run emulators:start
it works fine even after reloading the page, but if I edit (or just save without editing) any file it does a hot reload and then throws the error.
If I understand this correctly, the recommendation from @Janque is to modify the
getDatabase(...)
function in RTDB to only attempt to connect to to the emulator if the RTDB instance has not started? That is, make RTDB behave the same as Firestore in initialization.For general housekeeping, I'm going to remove the firestore tag from this issue.
Yes
@Janque - thanks for the example. I just wanted to make sure there wasn't a useEffect
or something similar that was calling getDatabase
multiple times as that's something I see from time-to-time.
While I think the change can be made, I'm unable to reproduce this issue. getServerSideProps
only seems to get triggered on full reload for me. What version of nextjs are you on?
@maneesht it's 13.0.2, but I just updated to 13.0.6 and it still happens. Start the emulators, all fine; edit and save a file like index.js; if the browser didn't reload by it self, I refresh the page and then the error.
Server Error
Error: FIREBASE FATAL ERROR: Cannot call useEmulator() after instance has already been initialized.
This error happened while generating the page. Any console logs will be displayed in the terminal window.
Source
fatal
file:///.../node_modules/@firebase/database/dist/node-esm/index.node.esm.js (311:11)
connectDatabaseEmulator
file:///.../node_modules/@firebase/database/dist/node-esm/index.node.esm.js (13732:9)
getDatabase
file:///.../node_modules/@firebase/database/dist/node-esm/index.node.esm.js (13713:9)
I just did the change that I suggested in my local package files and the problem is temporarily solved
// node_modules/@firebase/database/dist/node-esm/index.node.esm.js
function getDatabase(app = getApp(), url) {
const db = _getProvider(app, 'database').getImmediate({
identifier: url
});
if (!db._instanceStarted) {
const emulator = getDefaultEmulatorHostnameAndPort('database');
if (emulator) {
connectDatabaseEmulator(db, ...emulator);
}
}
return db;
}
@Janque I was able to reproduce the issue. Though the problem is a little more complicated than I originally had thought. The error comes from the connectDatabaseEmulator
that the user calls to connect to the emulator, not the one called by Database.ts
. If I add the extra check that you have, it still causes an issue for me. I'm checking with others on this.
@maneesht I never call connectDatabaseEmulator
directly in my code.
But when I did the change in my packages file the problem disappeared I guess because connectDatabaseEmulator
wasn’t being called more than once anymore.
After that change I haven’t had any issues with it as long as I don’t update.
That's very odd, do you have environment variables set up for your emulator port?
Not sure what you mean by "for the emulator port", but I don't have any .env files
Basically, getDefaultEmulatorHostnameAndPort
will look at your process.env.__FIREBASE_DEFAULTS__
to see if you have any emulator ports available, and if and only if you have that environment set up will it call connectDatabaseEmulator
. Do you have that env var defined? And is emulator
defined for you?
I appreciate your patience. The more information I know about your use-case, the better the subsequent tests will be.
Well I don't have any .env setup. So I guess no.
I only have the emulators config in the firebase.json
"emulators": {
"functions": {
"port": 5001
},
"firestore": {
"port": 8080
},
"database": {
"port": 9000
},
"hosting": {
"port": 5002
},
"pubsub": {
"port": 8085
},
"ui": {
"enabled": true
}
}
I'd maybe mention that the default hosting port was 5000 and I had to change it because some AirPlay feature (I think) uses it.
Also when I run the emulators I use firebase emulators:start --import emulators/emulator-fsdb
which imports a copy of my firestore db, but I don't think that has anything to do with the issue.
[REQUIRED] Describe your environment
[REQUIRED] Describe the problem
Steps to reproduce:
I'm using the nextjs integration with firebase database and when there is a hot reload (ex. saving a file), the following error appears: Error: FIREBASE FATAL ERROR: Cannot call useEmulator() after instance has already been initialized. From the line:
When there has been no hot reload, everything works fine.
After more investigation I found that the code that connects the emulator differs from the one that connects the firebase emulator
I believe that those changes would fix the issue.
My package.json dependencies