Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to initialize firebase in gatsby?

I'm stuck on making firebase work in my gatsby application that uses Redux with Redux-sagas. I know about the existence of firebase-sagas but I'm trying to make without using it.

I'm trying to init firebase auth by:

import * as firebase from 'firebase/app';
import 'firebase/auth';

export const app = firebase.initializeApp(
  {
    apiKey        : "apiKey",
    authDomain    : "project.firebaseapp.com",
    databaseURL   : "https://project.firebaseio.com",
    projectId     : "project",
    storageBucket : "project.appspot.com",
    appId         : "appId"
  }

)

export const authRef = () => app.auth(); //also tried: firebase.auth() and firebase.auth(app)
//firebase.auth returns a function, but firebase.auth() throws error

I have the following config on my gatsby-node.js:

const path = require('path');

exports.onCreateWebpackConfig = ({ actions, plugins, loaders, getConfig }) => {
  const config = getConfig()

  config.resolve = {
    ...config.resolve,
      mainFields: ['module', 'browser', 'main'],
      alias: {
        ...config.resolve.alias,
        ['firebase/app']       : path.resolve(__dirname, 'node_modules/firebase/app/dist/index.cjs.js'),
        ['firebase/auth']      : path.resolve(__dirname, 'node_modules/firebase/auth/dist/index.cjs.js'),
      }
  }

  actions.replaceWebpackConfig(config)
}

It trows the error:

{ [M [Error]: The XMLHttpRequest compatibility library was not found.]
  code: 'auth/internal-error',
  message: 'The XMLHttpRequest compatibility library was not found.' }

I think it's some problem related to webpack. I would love any insights on this problem :)

like image 357
Felipe César Avatar asked Oct 05 '19 07:10

Felipe César


People also ask

How do you initialize firebase in react?

Initialize Firebase using values that you can find at: // https://console.firebase.google.com/project/_/settings/general/ firebase. initializeApp({ apiKey: "web-api-key", projectId: "project-id" }); ReactDOM. render(<App />, document. getElementById("root")); serviceWorker.


1 Answers

As Gatsby builds pages in a server environment, you can't access Firebase during Gatsby build time. Firebase calls (using the Web SDK) have to happen when the user is on a browser/client environment.

One solution to this problem is creating a function like so:

firebase.js:

import firebase from '@firebase/app';
import '@firebase/auth';
import '@firebase/firestore';
import '@firebase/functions';

const config = {
   ... firebase config here
};

let instance;

export default function getFirebase() {
  if (typeof window !== 'undefined') {
    if (instance) return instance;
    instance = firebase.initializeApp(config);
    return instance;
  }

  return null;
}

This file returns a function, which returns an instance of Firebase if the user has the global window available (e.g. on the browser). It also caches the Firebase instance to ensure it cannot be reinitialised again (in case of the user changing page on your website).

In your components, you can now do something similar to the following:

import getFirebase from './firebase';

function MyApp() {
  const firebase = getFirebase();
}

As Gatsby will try to build this page into HTML during gatsby build, the firebase const will return null, which is correct, as the Firebase Web SDK cannot initialise on a server environment. However, to make use of Firebase on your website, you need to wait until Firebase is available (so the user has to have loaded your website), so we can make use of Reacts useEffect hook:

import React { useEffect } from 'react';    
import getFirebase from './firebase';

function MyApp() {
  const firebase = getFirebase();

  useEffect(() => {
    if (!firebase) return;

    firebase.auth().onAuthStateChanged((user) => { ... });
  }, [firebase]);
}

This works as Firebase is being used in a browser environment and has access to the browser, which is needed for the Web SDK to work.

It does have drawbacks; your compo have to return null in instances when you need Firebase to display content, which will mean your HTML build on the server will not contain any HTML, and it'll be injected via the client. In most cases though, such as an account page, this is fine.

If you need access to data from say Cloud Firestore to display page content, you're best using the Admin SDK to fetch content and add it to GraphQL during Gatsby build. That way it will be available on the server during build time.

Sorry if that was a waffle or not clear!

like image 104
Elliot Hesp Avatar answered Oct 20 '22 21:10

Elliot Hesp