Skip to content

Instantly share code, notes, and snippets.

@dyaa
Last active February 10, 2024 08:58
Show Gist options
  • Save dyaa/8f8d1f8964160630f2475fe26a2e6150 to your computer and use it in GitHub Desktop.
Save dyaa/8f8d1f8964160630f2475fe26a2e6150 to your computer and use it in GitHub Desktop.
Lazy Load Import Firebase (dynamic import)
Promise.all([
import('firebase/app'),
import('firebase/database'),
import('firebase/auth'),
])
.then(x => x[0].default)
.then(firebase => {
const config = {
apiKey: '',
authDomain: '',
databaseURL: '',
projectId: '',
storageBucket: '',
messagingSenderId: '',
}
firebase.initializeApp(config)
if (global.firebase) {
return global.firebase
} else if (!firebase) {
return Promise.reject(new Error('loading error'))
} else {
global.firebase = firebase
const googleAuthProvider = new firebase.auth.GoogleAuthProvider()
googleAuthProvider.addScope('https://www.googleapis.com/auth/userinfo.email')
global.firebase.googleAuthProvider = googleAuthProvider
return global.firebase ? global.firebase : firebase
}
})
.catch(err => {
throw new Error(err)
})
@Jaseibert
Copy link

@qxygene Yeah, I stopped on this thread during a 6-hour journey to find how to lazy load the treeshakeable imports for Firebase v9. Everyone seemed nice, so I came back with a solution. Shout out to https://twitter.com/gabe_ragland/status/1417516444686839809 for the og solution. Hope this helps anyone struggling on v9 like I was.

Firebase Setup

/***** firebase/app.js *****/

import fbConfig from "./config";
import { initializeApp, getApp, getApps } from "firebase/app";

const setupFirebase = () => {
  if (getApps.length) return getApp();
  return initializeApp( /* Your Firebase Config */);
};

export const app = setupFirebase();



/***** firebase/auth.js *****/

import { getAuth } from "firebase/auth";
import { app } from "./app.js";

// Export initialized Firestore "auth"
export const auth = getAuth(app);

//Export just what you need
export {
  signInWithEmailAndPassword,
  createUserWithEmailAndPassword,
} from "firebase/auth";



/***** firebase/firestore.js *****/

import { getFirestore } from "firebase/firestore";
import { app } from "./app.js";

// Export initialized Firestore "DB"
export const db = getFirestore(app);

//Export just what you need
export {
  collection,
  query,
  where,
  orderBy,
  onSnapshot,
} from "firebase/firestore";

Usage in Project

// Dynamically import subset of Auth Methods
const getAuth = () => import("../firebase/auth.js")

// Dynamically import subset of Firestore Methods
const getDb = () => import("../firebase/firestore.js")

/**
* Get them both at the same time
* Usage: const { firestore: { db, query, collection, where, orderBy, onSnapshot } } = await getFirebaseAll()
*/
const getFirebaseAll = () => {
  return Promise.all([
    import("../firebase/auth"),
    import("../firebase/firestore"),
  ]).then(([auth, firestore]) => {
    return { auth, firestore };
  });
};

/****** Example ******/

const onSignup = async (email, password) => {
    // Use await to ensure the library is loaded 
    const { auth, createUserWithEmailAndPassword } = await getFirebase()

    // Call the method like normal
    const { user } = await createUserWithEmailAndPassword(auth, email, password)

    // Do whatever else
} 

credit: https://twitter.com/gabe_ragland/status/1417516444686839809

@qxygene
Copy link

qxygene commented Feb 17, 2022

thank you, works nice. But one thing for auth; when i refresh page and update doc, i receive an error => FirebaseError: Missing or insufficient permissions. If i dont refresh page all works fine.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
 match /users/{document=**} {
      allow read;
      allow write: if request.auth != null;
    }
  }
}

@augustmuir
Copy link

augustmuir commented Apr 6, 2022

@Jaseibert Thanks this works great.

To add on, I also made my own firebase types/interface files (I am using typescript), then I re-wrote firebase code I needed to use which I couldn't wait for (such as Timestamp) in my own files without the bloat. Lastly I made sure I absolutely never imported from firebase/(any of them) outside of the root firestore files were created from your guide.

The second step of the optimization I explained above took and extra 125kB+ off the bundle. After optimizing just firebase my first load JS shared by all went from 320kB to 125kB! (I use functions, storage, firestore, and auth)

You can use this eslint rule to prevent importing firebase directly:
"no-restricted-imports": ["error", "firebase/app", "firebase/firestore", "firebase/storage", "firebase/auth", "firebase/functions"]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment