Firebase

Creating a Vue SPA with Google Firebase

A typical single page application (SPA) can’t work properly without an API to fetch data. Normally, we use Laravel for this but Google’s Firebase project seemed a good option as well, especially for quickly creating a minimum viable product. In this post, I’ll discuss some issues I ran into while working on a side project called ‘My Books’.

The basic idea for this app came to my mind when I wanted to buy a new book from Stephen King. Currently, I have read 20 to 30 books of this writer and I sometimes struggle to remember which books I read before and which ones I have in my collection. So I decided to build a little app to help me with this.

My Books

When thinking about the requirements and specifications of this app, I came to the following:

  • A book has a title, writer and genre. Additionally, it might be in your collection (or not) and you may have completed the book already.
  • A user should be signed in to see his books, add a book, etc.
  • Sign in with a Google Account should be possible (and is the only option at the moment).
  • The app should be hosted on Firebase as it seems relatively simple and free (at least for the Spark tier I am currently on).
  • The app should be coupled with a personal domain.
My Books homepage

Project setup

I implemented the app using Vue with Vue Router and Vuex. Instead of scaffolding using the Vue CLI, I found the VueStacks website with demo projects via the Vue developers newsletter. From the list of demos, I found a ‘task manager app’ setup with Firebase. This demo seemed a good starting point to be modified into my books app, so I started from there. 

The demo application is configured to use a Firebase database, so that part is covered. However, authentication was not part of this demo.

Please note that at the moment, VueStacks seems to be offline, which is a pity.

From tasks to books

First I had to connect my copy of the demo to my firebase backend. So I created a project within the Firebase console and copied the credentials to my firebase.json file. It worked as expected, so I proceeded to change the app to incorporate my books, writers and so on, then deleted everything that was related to tasks and I had my app running locally with a Firebase backend. 

Sign in with Google

Instead of implementing a basic sign-in form for the books app myself, authentication using a Google account seemed much more convenient since this is already baked in in Firebase. So the only task that remained was to wire everything together.

First of all, we need a button. Clicking the button (for an unauthenticated user that is) should sign in the user with his Google account. 

Within the Firebase JS module, there is an auth module. Import this module and use it in the click handler of the button like so

const provider = new firebase.auth.GoogleAuthProvider()
await firebase.auth().signInWithPopup(provider)

Now comes the tricky part, as we need a way to store the user in the state of our application. Luckily the firebase auth module helps here as well. It has an ‘onAuthStateChanged’ method that is fired once someone signs in or signs out. On sign-in, the user is passed as payload. On sign out, nothing is passed and the payload is empty.

We simply use this method to update our state on sign in and sign out like so:

// When ever the user authentication state changes write the user to vuex.
firebase.auth().onAuthStateChanged((user) => {
    if (user) {
        store.dispatch('setUser', user);
    } else {
        store.dispatch('setUser', null);
    }
});

Once the sign-in button is clicked and the user is signed in to My Books, we have the user in the state. We use this to define a computed property ‘userAuthenticated’ which comes in handy in various parts of the app.

Based on the userAuthenticated property, we show either the sign in or sign out button.

Protecting the database with rules

Reading and writing data from the Firebase database is quite easy and was set up already in the sample code I used as a starter kit. I just had to rename the collections and I was good to go.

However, it is strongly advised to add rules for your database to ensure the data is safe. For example, in My Books, we have collections of books, writers and genres. Users may add books and writers (if signed in), but no genres. Additionally, users may only retrieve their own books and naturally, they are not allowed to update or delete a book from someone else.

Rules can be set up in the Firebase console, which you can read more about in the official docs or this post. However, even with all these resources, it took me quite some time to get my rules correct.

Not to mention my queries that retrieve the data. For example, given the rule ‘thou shall not retrieve books that are not yours’, the query to get your books must contain a 

where('user', '==', userId)

part. Otherwise, the query will not work as expected and an error pops up in the developer console.

Setup firebase hosting and deploy the code

One of the great benefits of Firebase is, without doubt, the hosting feature. You can simply host your app, even on a personal domain (see next section).

Again, it took some time to get it working, although the official docs came in handy again.

First of all, I installed the firebase-tools package from npm globally. Then I was able to sign in from the command line by executing ‘firebase login’ which opens your browser to sign in with a Google account.

After sign in succeeded, the following step is to execute ‘firebase init hosting’. I had some trouble finding out in which folder I had to run this command. In the end, I ran the command from the root of the project.

The command is

firebase init hosting

followed by

firebase deploy

but somehow I ended up with my index.html file being overwritten in the dist folder. Building for production again and deploying did work in the end.

Whenever you add a new feature to the app you need to deploy again. Simply build the app for production, sign in with firebase and deploy by using these commands

npm run build
firebase login
firebase deploy

Add a personal domain and fix authentication

So now we have our app online on a Google domain, but I did not like the domain name. It was automatically created and combines the title of my app ‘booksapp’ with the id of my app and extension .web.app or .firebaseapp.com.

Luckily, it’s possible to connect your domain to the app. First, make sure you have a domain ready. Inside the hosting panel of the firebase console, you simply add your domain in two steps:

  1. Enter your domain name
  2. Add two DNS records as shown in the interface (you add these records where you can do this yourself for the domain you chose in step 1).

Then, you just wait for a little for the DNS records to become active.

Finally, when you have authentication set up for your app, your domain name needs to be whitelisted before you can sign in again from this domain. Head over to the authentication panel of firebase. You’ll find authorized domains below the login methods. Simply add your domain and you should be good to go.

Concluding remarks

This was my journey setting up a Vue project using the Firebase console. Authentication out of the box, simple database set up, free hosting and the possibility to couple a personal domain are all very good reasons to use this setup to quickly test a new idea for an app.

However, Google’s products may change in the future, or the free tier might become less generous. For more complex apps with more tables and relations, I still believe that a Laravel API with MySQL database is better suited, but this is also a lot more work to set up.

Coverphoto by raquel raclette on Unsplash


Mijn Twitter profiel Mijn Facebook profiel
Pim Hooghiemstra Webdeveloper and founder of PLint-sites. Loves to build complex webapplications using Vue and Laravel! Latest post
Creating a Vue SPA with Google Firebase

Leave a Reply

Your email address will not be published. Required fields are marked *