DEV Community

loading...
Cover image for No-Nonsense Firebase Auth + Firestore in Vue

No-Nonsense Firebase Auth + Firestore in Vue

terabytetiger profile image Tyler V. (he/him) Originally published at terabytetiger.com ・2 min read

Let's add Firebase to our Vue + Vuex App with no nonsense.

Tip: Ctrl + F for "recipe" to find variables to update

NPM

npm i firebase core-js
Enter fullscreen mode Exit fullscreen mode

Config Files

Add src/firebase.js:

import * as firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";
// 👆 This example is using Auth + Firestore

var firebaseConfig = {
  // This comes from Google - add your config here
};
firebase.initializeApp(firebaseConfig);

// utils
const db = firebase.firestore();
const auth = firebase.auth();

// collections
const usersCollection = db.collection("users");
const recipeCollection = db.collection("recipe");
// 👆 Here you create your Collections you want to use later

// 👇 You export things here | update the variable names
export { db, auth, usersCollection, recipeCollection };
Enter fullscreen mode Exit fullscreen mode

Modify src/main.js

// 👇 Add this to your imports
import { auth } from "./firebase";

// 👇 Wrap your new Vue like this
let app;
auth.onAuthStateChanged(user => {
  if (!app) {
    app = new Vue({
      router,
      store,
      render: h => h(App)
    }).$mount("#app");
  }

  if (user) {
    store.dispatch("fetchUserProfile", user);
  }
});
Enter fullscreen mode Exit fullscreen mode

Vuex Store

Template State

// 👇 Add these imports
import * as firebase from "../firebase";
import router from "../router/index";

// 👇 Add this outside your store const if it isn't user dependent filtering
firebase.recipeCollection
      // 👆 Replace this with your variable from firebase.js
  .where("public", "==", true)
        // 👆 This filters incoming data
  .onSnapshot(snapshot => {
    let recipeArray = [];

    snapshot.forEach(doc => {
      let recipe = doc.data();
      recipe.id = doc.id;

      recipeArray.push(recipe);
    });
  // 👆 Create an array of all docs found. 
    store.commit("setRecipes", recipeArray);
  });

// 👇 From here down replaces the export default new Vuex.Store({...}) that Vue adds by default
const store = new Vuex.Store({
  state: {
    userProfile: {},
    recipes: []
  },
  mutations: {
    setUserProfile(state, val) {
      state.userProfile = val;
    },
    setRecipes(state, val) {
      state.recipes = val;
    }
  },
  actions: {
    async login({ dispatch }, form) {
      const {
        user
      } = await firebase.auth.signInWithEmailAndPassword(
        form.email,
        form.password
      );

      dispatch("fetchUserProfile", user);
    },

    async fetchUserProfile({ commit }, user) {
      const userProfile = await firebase.usersCollection
        .doc(user.uid)
        .get();

      commit("setUserProfile", userProfile.data());

      if (router.currentRoute.path === "/login") {
        router.push("/");
      }
    },
    async logout({ commit }) {
      await firebase.auth.signOut();

      // clear userProfile and redirect to /login
      commit("setUserProfile", {});
      router.push("/login");
    },

    async createRecipe({ state, commit }, recipe) {
      let now = new Date();

    // 👇 Model your record here
      await firebase.recipeCollection.add({
        createdOn: now,
        userId: firebase.auth.currentUser.uid,
        username: state.userProfile.name,
      });
    },

    async signup({ dispatch }, form) {
      // sign user up
      const {
        user
      } = await firebase.auth.createUserWithEmailAndPassword(
        form.email,
        form.password
      );

// 👇 Add this to your login form as the submit function
//    login() {
//      this.$store.dispatch("login", {
//        email: this.loginForm.email,
//        password: this.loginForm.password
//      });
//    },

      // create user profile object in userCollection
      await firebase.usersCollection.doc(user.uid).set({
        name: form.name
      });

      dispatch("fetchUserProfile", user);
    },
  }
});

export default store;
Enter fullscreen mode Exit fullscreen mode

V-Router

// 👇 Add this to your imports
import { auth } from "../firebase";

// ...

// 👇 An example route that requires user to be authenticated
const routes = [
  {
    path: "/",
    name: "Home",
    component: Home,
    meta: {
      requiresAuth: true
    }
  },
]

// ...

// 👇 Add this just before your export 
router.beforeEach((to, from, next) => {
  const requiresAuth = to.matched.some(
    x => x.meta.requiresAuth
  );

  if (requiresAuth && !auth.currentUser) {
    // 👇 Direct the user to this path if not logged in
    next("/login");
  } else {
    next();
  }
});
Enter fullscreen mode Exit fullscreen mode

References

These sources helped me get this working the first time:

Discussion (0)

pic
Editor guide