X-Team Blog - The Most-Loved Company for Engineers

Creating with Vue 2.5, Vue Router, and Firebase

Written by Adam Gerard | Apr 17, 2018 4:00:00 AM

Hey Everyone! I'm brand new to X-Team and wanted to start off my career here by diving into a cool and increasingly well-used framework called Vue!

Vue's right up there with Angular 5 and React as a viable and easy way to use a Frontend framework for web and mobile development.

Our adventure will take us through setting up Vue 2.5, routing using Vue Router, integrating Firebase for data, and incorporating webpack 3.6 to transpile it all up.

We'll be building our own VueFire using Vue 2.5 and webpack 3.6.

Taking the Long Vue

Vue 2.5 now has a large open-source following with over 90K stars, 188 contributors, and over 13K forks on its core repos alone.

The version we'll be using in this article, Vue 2.5, was released back in October 2017.

Additionally, it has increasing support for mobile through Cordova (several plugins now exist to simplify the process), full-fledged routing through Vue Router, UI component library support through frameworks like Veutify, and state management through Veux.

As such, you might find Vue to be a useful alternative when deciding how to build your app!

Firebase

Firebase provides a suite of cloud solutions including an oustanding event-driven real-time NoSQL database that is simple to provision.

There are some useful features that are idiosyncratic to Firebase that can greatly improve the performance of your applications. For example, Firebase supports efficient nested querying in lieu of support for Arrays or Lists natively (Arrays and Lists require iterated searches to query).

Setting Up an Account

Signing up for Firebase is super easy — you can login with your usual Gmail account at firebase.google.com:

Which will then populate with your app information:

After which we'll be directed to the welcome page where we can grab our app credentials:

We'll then add Firebase to our package.json:

    "firebase": "=4.12.1"

Preparing our Data

Next up, we'll want to populate our Firebase database with some data:

{
    "contacts" : {
        "0001" : {
            "description" : "a dude guy",
            "email" : "adam.gerard@x-team.com",
            "first_name" : "Adam I.",
            "last_name" : "Gerard"
        },
        "0002" : {
            "description" : "rockstar scientist",
            "email" : "science@iscool.com",
            "first_name" : "Mme. Marie",
            "last_name" : "Curie"
        },
        "0003" : {
            "description" : "visionary",
            "email" : "phil@osophy.us",
            "first_name" : "Ludwig",
            "last_name" : "Wittgenstein"
        },
        "0004" : {
            "description" : "extraordinary ",
            "email" : "human.being@person.me",
            "first_name" : "Just An",
            "last_name" : "Everyperson"
        }
    }
}

And, for our limited testing and development purposes, we'll provide public access for our database:

{
  "rules": {
    "users": {
      ".read": "true",
      ".write": "true"
    }
  }
}

Not to worry though, we'll go over how to incorporate advanced security features for Firebase in a later article!

Setting up Vue 2.5

We'll focus on the following two core Vue 2.5 dependencies:

  "vue": "=2.5.16",
  "vue-router": "=3.0.1"

webpack 3.6

For transpiling our ES6 and .vue files into browser-compliant ES5 scripts, we'll need to use a good build tool. For this article, we'll stick with webpack 3.6 (and will focus on later versions of webpack in future articles) since it's also the version used in the current Vue-CLI webpack module. Vue can be a be a bit tricky to set up the first time (or when upgrading from earlier versions).

Stick the following .babelrc into your project root:

{
  "presets": ["stage-0", "env"]
}

Our build-related package.json dependencies will be:

    "babel-core": "=6.26.0",
    "babel-loader": "=7.1.4",
    "babel-preset-env": "=1.6.1",
    "babel-preset-stage-0": "=6.24.1",
    "css-loader": "=0.28.11",
    "extract-text-webpack-plugin": "=3.0.2",
    "vue-loader": "=14.2.2",
    "vue-style-loader": "=4.1.0",
    "vue-template-compiler": "=2.5.16",
    "webpack": "=3.6.0"

Our chosen dependencies give us the ability to minifiy css and transpile, minify, uglify, and lint both .js and .vue!

Here, our webpack.config.js will have the following rules:

    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        include: [resolve('src')]
      },
      {
        test: /\.css%/,
        loader: 'css-loader'
      }
    ]

live-server

live-server is a great lightweight alternative to webpack dev server. live-server supports hot-reloading and what I've found to be the simplest configuration for a tool of its kind.

Our package.json should include in its dependencies:

  "live-server": "=1.2.0",

And we can control the server's configuration settings in a custom script hotserver.js:

const liveServer = require("live-server"),
  params = {
    port: 8181,
    root: "./public",
    file: "index.html",
    wait: 1000,
    logLevel: 2
  };

liveServer.start(params);

Which we can start using node hotserver.js.

Vue 2.5 Application

Let's dive into Vue 2.5! To start, let's think about the overall layout for our app:

root
├── Components
|   └── //... Vue presentation components
├── Firebase
|   └── //... Firebase helpers here
├── Router
|   └── //... Router here
├── App.vue
└── main.js

Accordingly, we'll divide our app by component type or function (separation of concerns).

Entry

Our Vue app attaches to a specified HTML element through main.js:

import Vue from 'vue'
import { Router } from './Router'
import App from './App.vue'

const assembledApp = new Vue({
  Router,
  render: createElement => createElement(App)
})

assembledApp.$mount('#vueApp')

Vue Components

The basic anatomy of a .vue file looks like this:

<template></template>

<script></script>

<style scoped></style>

Let's take a closer look at those three parts — we have:

  1. the markup which is placed between the <template> tags,
  2. the component logic located in between the <script> tags, and
  3. the styling which is placed between <style> tags.

The scoped attribute on a <style> tag limits the styles to the markup specified in the component!

Of these three sections, the <script> tags are probably the most complicated.

Script

The <script> tags of any .vue file contains the logic, data, methods, exports, and lifecycle of the component.

<script>
  import NestedComponent from './NestedComponent.vue'

  export default {
    components: {
      NestedComponent
    },
    data () {
      return {
        exampleObject: {},
        exampleArray: []
      }
    },
    mounted () {
      this.example()
    },
    methods: {
      example: () => //..
    }
  }
</script>

Every component must be exported in the <script> tags:

 export default {
  //...
 }

We specify nested components in components for use within <template> tags.

Readers familiar with Angular 1's $scope will find the data() method to provide a similar way to stipulate different objects and data structures that can be accessed within the view. For example, we can iterate through them or place them strategically as needed:

<tbody>
  <tr v-for="example in exampleArray">
      <th></th>
        <th></th>
    </tr>
</tbody>
<div></div>

methods() function specifies methods that can be bound to DOM elements or used during the many phases of the Vue 2.x lifecycle.

We'll take a deeper dive into the Vue 2.x lifecycle in another article but feel free to check out official docs if you're hungry to learn more now!

Routes

Our Vue Router looks like:

import Vue from 'vue'
import VueRouter from 'vue-router'
import ExampleComponent from '..'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    component: ExampleComponent
  },
  //...
]

export const router = new VueRouter({
  mode: 'history',
  routes
})

One big gotcha (that got me) is that VueRouter must be exported as router exactly (no upper-case Router allowed)!

Working With Firebase

We can initialize our Firebase helpers here:

import * as firebase from 'firebase'

const config = {
  apiKey: '...',
  authDomain: '...',
  databaseURL: '...',
  projectId: 'x-team-vue-app',
  storageBucket: '',
  messagingSenderId: '...'
}

const db = () => {
    firebase.initializeApp(config)
    return firebase.database()
}

Core CRUD functionalities are expressed:

  fetchAll: (db, ref) => new Promise((resolve) => {
    db.ref(`/${ref}`)
      .once('value')
      .then(v => resolve(v.val()))
  }),

  /** GET One */
  fetchOne: (db, ref, key) => new Promise((resolve) => {
    db.ref(`/${ref}/${key}`)
      .once('value')
      .then(v => resolve(v.val()))
  }),

  /** POST One */
  addOne: (db, ref, key, contactData) => new Promise((resolve) => {
    resolve(db.ref(`/${ref}`).child(key).set(contactData))
  }),

  /** DELETE One */
  removeOne: (db, ref, key) => new Promise((resolve) => {
    resolve(db.ref(`/${ref}`).child(key).remove())
  })

We can then import our new Firebase helper in the script tags of any component where we'd like such functionality!

Conclusion

That's it! We've set up Vue 2.5 with routing and webpack 3.6! The code used in this article is available on GitHub: github.com/Thoughtscript/x_team_vue.

In the future, we'll cover how to add clientside state management systems like Veux, dive deeper into the Vue Lifecycle, leveraging Vue for mobile, upgrade from webpack 3.6 to 4, and more so stay tuned!