Go back to the basics with Firebase using JavaScript 1227 words.
Last Updated
Today we’re going back to the basics in Firebase by building a basic web app from scratch. Even though this is beginner level, I think it’s very useful to write code with Firebase using nothing but plain JS, especially if you’re used to developing with a framework library like AngularFire, ReactFire, or Vuefire. In addition, I want give you my Why Firebase? opinion and explain why it’s my goto cloud provider.
What is Firebase?
Firebase is a Backend-as-a-Service, which really boils down two things - (1) A container for Google Cloud Platform resources, and (2) a collection of SDKs to interact with these resources from the web, iOS, Android, Unity, and more.
Why Firebase? Why not AWS or Heroku?
Firebase does not compensate me to say nice things, I am just a happy customer :)
In my opinion, Firebase offers the quickest path to get your app in the hands of users. It accomplishes this by simplifying virtually all of your backend development concerns. As an independent developer, this boils down to three main pillars:
- An excellent developer experience.
- Minimization of cloud computing costs.
- Maximization of feature delivery per hour spent on development.
Pricing is free for small simple projects, then scales up linearly with volume. This pricing model is much more predictable than say Heroku, where you have to pay for dedicated servers and will eventually reach a very expensive pricing tier when your app moves beyond a minimal threshold.
AWS has an amazing selection of services and is the open cloud leader by far, but the developer experience is lacking by comparison. The UI looks like it was built with the original Twitter Bootstrap, but more importantly, the services often feel disjointed and hard to piece together. Firebase is a tightly integrated platform that follows the quality over quantity principle.
1. Hosting and Deployment
You can use any IDE for this project, but I will be using VSCode. The only other requirement is that you have NodeJS and NPM installed on your local machine.
We will leverage the command line to easily initialize, test, and deploy our app - start by creating an empty directory and pulling up a terminal session in your editor.
Create a New Project
Every Firebase project is a container of GCP cloud infrastructure, such as your database, file storage buckets, hosting servers, etc.
Initialize and Serve an App
Install Firebase command line tools globally.
npm install -g firebase-tools
Then initialize your project. You can just stick to the default options.
firebase init hosting
That should have generated a public/
folder along with some config files. Serve up your app in the browser with.
firebase serve
That’s cool, but would you rather see your app on the real internet? Deploy it by running.
firebase deploy
This will host your app with a SSL certificate and global CDN caching - pretty awesome. Deploying any JS Framework app like Angular, Vue, or React is just as easy.
In the following sections, my goal is to show you how little code it takes to accomplish a meaningful task in Firebase. You can place this code inside of the <script></script>
of the document index.html
body that was generated by the CLI.
2. User Auth
We can login a user with Google OAuth with the magic signInWithPopup
method. This will save a JSON Web Token to the browser that identifies the user.
function googleLogin() {
const provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider)
.then(result => {
const user = result.user;
})
}
Run the function above by binding it to a button click event.
<button onclick="googleLogin()">
Login with Google
</button>
That should authenticate the user into your app and create the user in Firebase as shown below:
3. Cloud Firestore Database
The foundation of a Firebase app is the database. You can read a document in the database by (1) making a reference to it and (2) calling onSnaphot()
. This will not only read it, but also subscribe to realtime updates - an amazingly powerful feature if your app provides realtime feedback to users.
Let’s imagine our we have a database structure as shown above and want read this data with a realtime listener
const db = firebase.firestore();
// Reference the document
const myPost = db.collection('products').doc('CGl2Obsqagfm1DguguLS');
// Listen to realtime changes
myPost.onSnapshot(doc => {
const data = doc.data();
})
Firestore also has powerful methods to retrieve and filter collections of documents. If we wanted to get all products with a price greater than $23.00, we could perform a query that looks like where('price', '>=', 23)
. Instead of a single document, we get an array of documents that match this query.
const productsRef = db.collection('products');
const query = productsRef.where('price', '>=', 23)
query.onSnapshot(products => {
products.forEach(doc => {
const data = doc.data();
})
});
4. Storage
Storage is similar in principle to the database - make a reference to file path, then read, update, or delete it.
The snippet below will push your file from the browser to the storage bucket.
<input type="file" onchange="uploadFile(this.files)">
function uploadFile(files) {
const storageRef = firebase.storage().ref();
const imgRef = storageRef.child('horse.jpg');
const file = files.item(0);
const task = imgRef.put(file)
// successful upload
task.then(snapshot => {
const url = snapshot.downloadURL
})
// monitor progress
task.on('state_changed', snapshot => {
console.log(snapshot)
})
}
Run this code and you should see your selected image in the Firebase storage bucket.
5. Cloud Functions
Cloud functions give you an on-demand backend NodeJS server. Instead of deploying a server that is active 100% of the time, functions spin up a server instance only when invoked. Why might you need that?
- Access server-side APIs (Stripe, SendGrid, Twilio).
- Run CPU intensive background tasks.
- Database aggregation
- Custom authentication flow
And much, much more. Checkout the Cloud Functions Feed for inspiration.
Initializing Functions
Cloud functions are an isolated NodeJS environment, so don’t confuse them with your frontend code. You can initialize this environment in your project by running:
firebase init functions
Simple Firestore Function
The function code below will listen to the the products
collection in Firestore, and run this code whenever a new document is created.
exports.sendMessage
that’s the name of our Function..document('products/{productId}').onCreate
runs the function when a new product doc is created.return productRef.update
remember to return aPromise
inside the function callback.
const functions = require('firebase-functions');
const admin = require("firebase-admin");
admin.initializeApp();
exports.sendMessage = functions.firestore
.document('products/{productId}')
.onCreate(event => {
const docId = event.params.productId;
const name = event.after.data().name;
const productRef = admin.firestore().collection('products').doc(docId)
return productRef.update({ message: `Nice ${name}! - Love Cloud Functions`})
});
Now deploy your backend with the following command.
firebase deploy --only functions
If you create a new product document in Firestore, you should see the message updated by the cloud function a few milliseconds later.
6. Analytics, Testing, Push Messaging, and Beyond
Mobile developers have even more great tools at their disposal thanks to Firebase’s acquisitions of Fabric and Appurify. These features go beyond the core resources of this lesson, but they give you even more tools to test, analyze, and monetize your project.
So much has changed in Firebase during the last year and I’m excited to see what drops next in the platform. Get in touch on Slack if you want to chat in more detail me.