How to migrate to modular Firebase SDK: A quick guide

patricklusaya

Patrick Lusaya

Posted on July 27, 2024

How to migrate to modular Firebase SDK: A quick guide

Imagine you’re packing for a trip. Instead of throwing everything from your closet into your suitcase, you only pack what you need for the journey. Not only does this make your suitcase lighter, but it also means you’re more organized and can find things easily.

Well, Firebase has done something similar with their new update! They’ve introduced a new way to use their tools that’s all about packing only what you need. This new method is called "modular Firebase," and it’s all about making your app faster and easier to manage.

In the past, using Firebase was a bit like taking everything from your closet – it worked, but it wasn’t always the most efficient. Now, with Firebase version 9 and later, you can pick and choose exactly what parts of Firebase you need, making your app lighter and quicker.

Hey, follow me on twitter, I'll help you with something ... I promise

In this article, i’ll show you how to switch from the old way of using Firebase to the new modular way

1.Initialize Firebase

Just like you wouldn’t pack your whole closet, you only import the Firebase parts you need.Create a file called firebaseConfiguration, paste the following code imports the required Firebase modules, configure Firebase with your project's settings, initialize Firebase and its services, and check if Firebase is already initialized in your app.

import { initializeApp, getApp, getApps } from 'firebase/app';
import { initializeAuth, getReactNativePersistence } from 'firebase/auth/react-native';
import { getFirestore } from 'firebase/firestore';
import { getStorage } from 'firebase/storage';
import AsyncStorage from '@react-native-async-storage/async-storage';

const firebaseConfig = {
    apiKey: "yourApiKey",
    authDomain: "yourAuthDomain",
    projectId: "yourProjectID",
    storageBucket: "yourStorageBucket",
    messagingSenderId: "yourMessagingSenderID",
    appId: "yourAppID",
    measurementId: "yourMeasurementID"
};

const app = initializeApp(firebaseConfig);
const auth = initializeAuth(app, {
    persistence: getReactNativePersistence(AsyncStorage)
});
const db = getFirestore(app);
const storage = getStorage(app);

const isFirebaseInitialized = () => {
    const apps = getApps();
    if (apps.length === 0) {
        return false;
    }
    const app = getApp();
    const config = app.options;
    return !!config.projectId;
};

export { auth, db, storage,isFirebaseInitialized };
Enter fullscreen mode Exit fullscreen mode

We have exported auth, db , storage and isFirebaseInitialized so we can use them wherever we need in our app.

2.Use the Exported Modules

In our app's entry point, we'll start by checking if Firebase is properly initialized using our isFirebaseInitialized function. If Firebase is not initialized correctly, we’ll log a message indicating the issue. Otherwise, we’ll proceed with rendering our main app component.

import { View, Text } from 'react-native';
import React from 'react';
import { isFirebaseInitialized } from './firebaseConfiguration';

const App = () => {
  if (!isFirebaseInitialized()) {
    console.log('Firebase is not initialized with a valid projectId.');
    return null;
  }

  return (
    <View>
      <Text>App</Text>

    </View>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

3.Modular firebase in action.

Now, let's see modular Firebase in action by fetching, creating, updating, and deleting data.

Before modular Firebase, you might have imported everything from Firebase like this:

import * as firebase from 'firebase';

While this worked perfectly, it wasn't the best approach because it loaded the entire Firebase library, including parts you might not need. This made your app's bundle size larger and could slow down its performance.

Let's compare two fetch operations, one using the Previous Firebase SDK and the other using the new modular firebase SDK

Previous Firebase SDK
In the previous Firebase SDK, you would import everything from Firebase, which could lead to larger bundle sizes and slower performance.

import firebase from "firebase";

const fetchData = async () => {
  const querySnapshot = await 
  firebase.firestore().collection('yourCollectionName').get();
  querySnapshot.forEach((doc) => {
    console.log(`${doc.id} => ${doc.data()}`);
  });
};

fetchData();
Enter fullscreen mode Exit fullscreen mode

Modular firebase sdk
With modular Firebase, we only import the specific modules we need at any given moment. This is more efficient and helps keep our app lightweight and fast.

import { collection, getDocs } from 'firebase/firestore';
import { db } from './firebaseConfiguration';

const fetchData = async () => {
  const querySnapshot = await getDocs(collection(db, 'yourCollectionName'));
  querySnapshot.forEach((doc) => {
    console.log(`${doc.id} => ${doc.data()}`);
  });
};

fetchData();
Enter fullscreen mode Exit fullscreen mode

Instead of loading the entire Firebase library, we have just imported the modules that we needed, collection and getDocs.

By importing only the necessary modules, we keep our code clean and efficient. This modular approach makes our app faster and easier to manage, especially as it grows in complexity. Now, let’s take a look at the complete CRUD operations using both the previous Firebase SDK and the new modular Firebase SDK.

Create Data
Previous SDK

import firebase from "firebase";
const createData = async () => {
  try {
    const docRef = await 
      firabase.firestore().collection('yourCollectionName').add({
      field1: 'value1',
      field2: 'value2'
    });
    console.log('Document written with ID: ', docRef.id);
  } catch (e) {
    console.error('Error adding document: ', e);
  }
};

createData();
Enter fullscreen mode Exit fullscreen mode

Modular firebase

import { collection, addDoc } from 'firebase/firestore';
import { db } from './firebaseConfiguration';

const createData = async () => {
  try {
    const docRef = await addDoc(collection(db, 'yourCollectionName'), {
      field1: 'value1',
      field2: 'value2'
    });
    console.log('Document written with ID: ', docRef.id);
  } catch (e) {
    console.error('Error adding document: ', e);
  }
};

createData();
Enter fullscreen mode Exit fullscreen mode

Update Data
Previous Firebase SDK

import firebase from "firebase";

const updateData = async (id) => {
  const docRef = 
  firabase.firestore().collection('yourCollectionName').doc(id);
  try {
    await docRef.update({
      field1: 'newValue1'
    });
    console.log('Document updated');
  } catch (e) {
    console.error('Error updating document: ', e);
  }
};

updateData('yourDocumentId');
Enter fullscreen mode Exit fullscreen mode

Modular Firebase SDK

import { doc, updateDoc } from 'firebase/firestore';

const updateData = async (id) => {
  const docRef = doc(db, 'yourCollectionName', id);
  try {
    await updateDoc(docRef, {
      field1: 'newValue1'
    });
    console.log('Document updated');
  } catch (e) {
    console.error('Error updating document: ', e);
  }
};

updateData('yourDocumentId');
Enter fullscreen mode Exit fullscreen mode

Delete Data
Previous Firebase SDK

import firebase from "firebase";
const deleteData = async (id) => {
  const docRef = 
  firabase.firestore().collection('yourCollectionName').doc(id);
  try {
    await docRef.delete();
    console.log('Document deleted');
  } catch (e) {
    console.error('Error deleting document: ', e);
  }
};

deleteData('yourDocumentId');
Enter fullscreen mode Exit fullscreen mode

Modular Firebase SDK

import { doc, deleteDoc } from 'firebase/firestore';

const deleteData = async (id) => {
  const docRef = doc(db, 'yourCollectionName', id);
  try {
    await deleteDoc(docRef);
    console.log('Document deleted');
  } catch (e) {
    console.error('Error deleting document: ', e);
  }
};

deleteData('yourDocumentId');
Enter fullscreen mode Exit fullscreen mode

Overall Arrangement and Syntax

  • collection(db, 'yourCollectionName'): Used to refer to a collection in Firestore.

  • doc(db, 'yourCollectionName', 'yourDocumentId'): Used to refer to a specific document within a collection.

  • Functions like getDocs, addDoc, updateDoc, and deleteDoc: These perform the actual operations on the data.

Pros of Modular Firebase

  • Smaller Bundle Size:

With modular imports, you only include the parts of Firebase you actually use, rather than the entire library.This reduces your app’s bundle size, leading to faster load times and better performance.

  • Improved Performance:

By importing only what you need, you minimize the amount of code that the JavaScript engine has to process. This can result in faster execution and reduced memory usage.

  • Tree-Shaking Support:

The modular approach supports tree-shaking, which is a technique to eliminate unused code during the build process.This further optimizes your app’s performance and reduces the final bundle size.

Cons of Modular Firebase

  • More Verbose Imports:

You need to import each function or module individually.This can make the import statements longer and potentially more cumbersome, though it provides clearer insights into what’s used.

  • Migration Effort:

Transitioning from the previous SDK to the modular SDK involves updating existing code and ensuring compatibility. This migration process can be time-consuming, especially for large projects with extensive use of Firebase.

That's pretty much it , adios !

Follow me on twitter, for more contents like these

💖 💪 🙅 🚩
patricklusaya
Patrick Lusaya

Posted on July 27, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related