2
votes

I started a project and occurred an error when importing firebase in more than one component.

In this firebase start file:

import firebase from 'firebase'
const firebaseConfig = {
  apiKey: "fdsfsdfdsf",
  authDomain: "fdsfdsfsdfdsf",
  databaseURL: "sdfdsfdsf",
  projectId: "dsfdsfdsf",
  storageBucket: "dsfdsfdsf",
  messagingSenderId: "dsfdsfsdfdsf"
}

const FbApp = firebase.initializeApp(firebaseConfig)

export default FbApp.auth()

Then in the components:

import firebase from '../lib/firebaseClient'

With a single component works well, but if I add a new component with:

import firebase from '../lib/firebaseClient' 

The application fail:

FirebaseError: Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app).

6
You should call initializeApp() in your app initialization/bootstrap methods, so that it's only done once. Not sure why react/next are completely invoking imports more than once though; seems like a bad model and like they would have solved this in a more useful way, so there's probably a solution to this on the react/next side as well. - Kato

6 Answers

8
votes

I had same issue, then I found out this:

if (!firebase.apps.length) {
  firebase.initializeApp({});
}

https://github.com/zeit/next.js/issues/1999

3
votes

The solution:

import firebase from 'firebase'

try {
  firebase.initializeApp({
    databaseURL: 'dfgdfg'
  })
} catch (err) {
  // we skip the "already exists" message which is
  // not an actual error when we're hot-reloading
  if (!/already exists/.test(err.message)) {
    console.error('Firebase initialization error', err.stack)
  }
}

const auth = firebase.auth()
export default auth
0
votes

My understanding is that the error is due to calling initializeApp() more than once for your database. Scan through your code to make sure you only call initializeApp() once. For me, this included checking any js files that might be calling the method and checking for duplicate js files in your html file.

I recently solved this error in my own code. My issue was caused by accidentally linking my javascript file, which calls initializeApp(), in the head and in the body of my html file. My fix was to delete the duplicate javascript tag in the head of my html file so only one existed in the body.

0
votes

On serverside something like this should work

const admin = require('firebase-admin');
const serviceAccount = require('./../../credentials/server');

// Check if firebase already been initialized
if (!admin.apps.length) {
  // Initialize Firestore.
  admin.initializeApp({
    credential: admin.credential.cert(serviceAccount),
  });
}
0
votes

Summarizing all good answers. A better fix would be to load environment variables from .env.local into process.env.

//.env.local
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
NEXT_PUBLIC_FIREBASE_APP_ID=

Next up, we can initialize the Firebase SDK on the client-side like this.

//shared/configs/firebase.js
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

const clientCredentials = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};

if (!firebase.apps.length) {
  firebase.initializeApp(clientCredentials);
}

export default firebase;

Finally, import the Firebase deps to other file.

//pages/index.js
import firebase from '../shared/configs/firebase';
0
votes

So I ran into this issue because of some aspect of Next's hot reloading. I was using code like the following to ensure that I didn't call initializeApp more than once:

export let adminClient;
adminClient = adminClient || admin.initializeApp({...});

This didn't work because it seemed like the hot reloading was clearing adminClient, so I kept trying to call initializeApp, even though firebase still had the app recorded as being initialized.

To fix this, I used the following snippet:

const getAppInstance = () => {
    if (admin.apps.length) {
        return admin.apps[0];
    } else {
        return initApp();
    }
}

export const adminClient = getAppInstance();

which works on a fresh server start, or when hot reloading due to code changes in development.