Leassons learned using Firebase for the first time
Tags: javascript, node, beginners, webdev
Published: 2020-11-09 10:54:10

A couple of weeks ago I decided that I wanted to build and launch a new project in a few days. To achieve that, I'd need to simplify as much as possible my tasks so I thought it was the perfect moment to learn Firebase and use it in a project for the first time. The project is still under development but so far I've learnt a few lessons I'd like to share.

## Why should you use Firebase?

The main reason I had to use Firebase was curiosity. I've been wanting to try it for a while now and with the launch of [AWS Amplify](https://aws.amazon.com/amplify/) (which is pretty similar) my curiosity kicked in again. But other factors can make you decide to choose Firebase. For example:

- Free plan: The free tier is good enough to build and run a small side project. It will give you 50k document reads, 20k document writes 20k document deletes, 1GB of stored data and 10GB of network. [See free plan details](https://firebase.google.com/docs/firestore/quotas#free-quota)

- Fast developing experience: writing an app from scratch requires a lot of time if you're writing every single piece of code. Just all the authentication workflows can take you a week or more so having all that built out of the box is a huge plus. With Firebase I just had to install a dependency in my front end, and forget about any back end code for authentication, APIs or data storage etc. The only thing I've had to write is Firestore rules (the ones used to control who can do what in your database) and those are super simple to use.

- Documentation: the [official docs](https://firebase.google.com/docs) are great and even include some Youtube video series like [this one for Firestore](https://www.youtube.com/watch?v=v_hR4K4auoQ&list=PLl-K7zZEsYLluG5MCVEzXAQ7ACZBCuZgZ). Also, there are tons of articles and videos on Youtube. My favourite is probably the [Fireship.io channel](https://www.youtube.com/channel/UCsBjURrPoezykLs9EqgamOA).


- Super simple deployments: With the Firebase CLI, deploying a Firebase project is as simple as running `firebase deploy`. No need to set up webhooks, clone your repo or anything like that. Just running a script and seeing your project live on a _.web.app_ domain, even with SSL enabled is awesome.

## My 8 tips when working with Firebase

I hope you find the reasons above enough compelling to try Firebase but before that, let me tell you a few tips that I think would make your project development event better:

### Use the Firebase CLI and VSCode extensions

You can install the CLI running `npm i firebase-tools -g` and then authenticate running `firebase login` with your Google credentials (did I mentioned Firebase is owned by Google?). In addition, the two VSCode extensions I installed are Firebase Explorer and Firestore Rules.

### Create two Firebase projects

In order to keep your develop and production environments completely isolated, I'd create two different projects in Firebase (for example _myAwesomeApp_ and _myAwesomeApp-dev_). Each project will have its own database, hosting and, more important, its own quotas so all the tests you'll do will not affect your live environment. You can create the project using the Firebase CLI or, better, create them manually in the [Firebase Console website](https://console.firebase.google.com/).

### Vuejs + Firebase project scaffold

As mentioned earlier, the project I'm creating is a web built with Vuejs so to start I ran `vue create my-project-name`. Then inside the project folder, run `firebase init` and selected the features you want, like _Hosting_ or _Firestore_ . Next, choose the development project you created in the previous step and finally, the CLI will ask you for the files where it'll define the Firestore rules and indexes. Once your project is scaffolded, you can do your first deployment!

### Setup deployment scripts for each environment/project

Once your Firebase project is initialized, you can deploy it running `firebase deploy`. This is ok to deploy to the Firebase project you chose when you initialized the project, but as we want to target different projects (remember we have develop and production), I suggest to create different scripts in your _package.json_ file. Here are the ones I have:

```json
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "deploy-rules-dev": "firebase deploy --project myAwesomeApp-dev --only firestore:rules",
    "deploy-rules-production": "firebase deploy --project myAwesomeApp --only firestore:rules",
    "deploy-functions-dev": "firebase deploy --project myAwesomeApp-dev --only functions",
    "deploy-functions-production": "firebase deploy --project myAwesomeApp --only functions",
    "deploy-dev": "vue-cli-service build --mode development && firebase deploy --project myAwesomeApp-dev",
    "deploy-production": "vue-cli-service build --mode production && firebase deploy --project myAwesomeApp"
  },
```
As you can see the firebase CLI has different flags we can use:
- _--project_ is used to select our target project
- _--only_ is used to select which part of our project we want to deploy.

### Use environment variables

This is very obvious but you should use environment variables to load you Firebase project keys or other variables that would be different in each environment. For example, initialise your app like this:

```js
// ⛔️ DONT
const firebaseApp = firebase.initializeApp({
  apiKey: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  authDomain: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  databaseURL: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  projectId: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  storageBucket: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  messagingSenderId: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  appId: 'xxxXXXXXxxXXXXxxXXXXxxxx',
  measurementId: 'xxxXXXXXxxXXXXxxXXXXxxxx',
})
// ✅ DO 
const firebaseApp = firebase.initializeApp({
  apiKey: process.env.VUE_APP_APIKEY,
  authDomain: process.env.VUE_APP_AUTHDOMAIN,
  databaseURL: process.env.VUE_APP_DATABASEURL,
  projectId: process.env.VUE_APP_PROJECTID,
  storageBucket: process.env.VUE_APP_STORAGEBUCKET,
  messagingSenderId: process.env.VUE_APP_MESSAGINGSENDERID,
  appId: process.env.VUE_APP_APPID,
  measurementId: process.env.VUE_APP_,
})
```
In my case, I'm using Vuejs so I just need to create two files named _.env.development_ and _.env.production_ locally and whenever I run `npm run build`, it will automatically replace the environment variables with the values from the correspondent file. You can read more about Vuejs environment variables [here](https://cli.vuejs.org/guide/mode-and-env.html).

### Think twice your data model and don't be afraid to duplicate

Before you start coding, think about how your app is going to look like, which data you are going to need in each page and which pages are going to be more used. This is pretty important because it will affect the way you'll store your data in Firestore (the noSQL database used in Firebase) or the Real Time Database. 

As one of the limitations of the free tier is the number of documents your app reads and writes, consider doing it just when you need it. 

One of the things that have made me save a ton of document reads is duplication of some fields. This is something not very common in relational databases (I'd say it's even forbidden 😅) where we use foreign keys and join queries but it's pretty normal in noSQL databases. You can read more about data modelling and view some videos [in this section of the docs](https://firebase.google.com/docs/firestore/manage-data/structure-data).

### Create functions for your Firestore rules

Once you start defining Firestore rules, there are two functions that you'll use all the time:
- validate if the request comes from a logged user
- validate if the user accessing a document is the one who created it

For that, you can create the following functions in your _firestore.rules_ file:

```js
//**** Functions   ****//
function isLoggedIn(){
  return request.auth != null;
}
function isOwner(){
  return request.auth.id ==resource.data.uid;
}
```

You can find more info about security rules [here](https://firebase.google.com/docs/firestore/security/get-started).

### Paginate and limit your queries

This comes back to the limitations of the free tier. Just remember to add a _limit(x)_ to your collection queries whenever you are going to access your data. You don't want to return 150 documents when on your page you can only display 20. 
Pagination is super simple to build thanks to the _startAfter()_ method. Find below an example of how I'm doing pagination in my Vuejs app:

```js
// part of store/index.js file

// global variable to store last paginated element
let paginationLast = null

// Vuex store action
getUpcomingTalks({ commit }, payload) {
  return new Promise((resolve, reject) => {
    talksCollection
      .orderBy('date', 'asc')
      .limit(payload.limit || 12)
      .startAfter(paginationLast)
      .get()
      .then((res) => {
        if (res.docs.length > 0) {
          // save last item for pagination
          paginationLast = res.docs[res.docs.length - 1]

          commit('GET_UPCOMING_TALKS', res.docs)
          return resolve()
        } else {
          reject({ hasMore: false })
        }
      })
      .catch((err) => {
        console.log('err in action :>> ', err)
        return reject()
      })
  })
},

```
Just remember:
- **limit** will limit the number of documents returned, pretty straight forward
- **startAfter** will tell Firestore what is the latest document you queried before. In my case, the first time I'll send it _null_, so it will start at the beginning of the collection. Then after each successful query, I update it with the last item so the following queries will start from it. **_Note_ that this has to be a document reference, not an id.**

## Conclusion

I still have a ton of things to learn about Firebase but I'd say these are the more important things I've learnt so far. Hope you find them useful.

If you liked this article, you can [follow me on Twitter](https://twitter.com/uf4no) where I share dev tips an insteresting articles and updates about the progress of my projects 🤙

Oh! and in case you're wondering, the project I'm building with Firebase is [QuickTalks.io](https://quicktalks.io) a place to organise and find talks for small audiences.

* * *

_This article was originally posted in [my blog](https://antonioufano.com/blog) where you can find other articles about web development focused on Laravel, Node.js Vue and more._