Basic Single Page application using Vue.js and Firebase — Part 1
In this tutorial I want to describe how to build a basic scaffold application with Vue.js and Firebase which includes:
- Authentication
- Real-time database
- Nice user interface based on material design
From technical point of view I will use the following:
- Vue.js — modern JavaScript framework
- Vue-router — for routing
- Vuex — for state management
- Firebase — for authentication, real-time database and hosting
- Vuetify — nice framework to create material design UI
This tutorial is not for complete beginners. The main prerequisite is knowledge of ES6 and at least basic knowledge of Vue.js. Having said that, any experience with front-end frameworks like React or Angular probably be sufficient. So let’s get started!
Setting up a project
First, install the official Vue.js command line interface (CLI) as follows:
npm install --global vue-cli
Now we are ready to start the project. For this app we will use Vuetify — a set of material design components compiled into framework. It helps to quickly create user interfaces and perfectly fits with Vue.js. Vuetify has a several predefined templates integrated with vue-cli, which you can use instead of default Vue.js starter project. To initialize new Vue/Vuetify project run:
vue init vuetifyjs/webpack demo-app
This command will download a Vuetify template and setup Webpack for you. During setup you’ll need to answer on application related questions. Firstly, choose your app name, project description, author (or just press Enter if you want the default values). Next few options are important for us. Answer “Runtime-only” for Vue build, “Yes” for installing vue-router, “Standard” ESLint preset, “No” for both tests. Also I don’t want “a-la-carte components” and a custom theme.
Open a project folder, install Webpack and start a development server (I will use NPM):
cd demo-app
npm install
npm run dev
After npm
finish installation of all dependencies (about minute or so) you will see development server up and running at localhost:8080
:
Cool. We have working development server.
Basic layout
Now, source code for this app you can find under /src
. In this folder you can see two files and several folders. File main.js
is a main entry point of your app, App.vue
is a single file component attached to your application. Under /assets
folder you can store static assets, /components
contains other single file components, /router
is for routing.
Our initial homepage looks fine. You can definitely use this code as a starting point. Instead, I want to start from scratch. For now I want to have only toolbar at the top and a navigation sidebar which appears only on small devices. Here is the code of App.vue
:
Let’s see what we have here.
In <template>
section I first added v-app
tag because it’s a requirement of Vuetify. Inside v-app
we have a three components.
Component v-navigation-drawer
is a sidebar menu which will appear on a small screen (width less than 576px). Sidebar is controlled by v-model="sidebar"
, we change the value of sidebar
by clicking on toolbar’s side icon.
Component v-toolbar
represents top bar. Inside toolbar there is v-toolbar-side-icon
which represents a burger icon. This icon you can see only on devices with small screens (because of class hide-sm-and-up
). This icon opens a sidebar by listening of click event (@click = "sidebar != sidebar
). v-toolbar-title
represents app title, v-spacer
is a spacer element which will help us later when we introduce addition menu items.
Finally, v-content
is a wrapper for Vuetify grid. Here we will render our main content.
Those and many other components of Vuetify library you can find in their documentation. Highly recommend you to look through it.
In <script>
section I only declared two data variables.
Routing
Great! Now we have a scaffold for our app. Let’s add routing.
We already have the router installed in our app in /router/index.js
. It is not connected with routes though. So now it’s a good idea to create a few views and then connect them to router.
Under /components
folder create several files with names Landing.vue
, Signin.vue
, Signup.vue
and Home.vue
(existing HelloWorld.vue
you can delete later). The purpose of those views is simple. Landing
will be generated on a root path /
, Home
will be a view for an authorized users. Signup
and Signin
speaks for themselves. For now let’s keep these views simple and skip any functionality behind them. Here is a code for Landing.vue
:
Three other files will be pretty much the same. Just copy this code to others, content we will add later. Now let’s configure our router. Open /router/index.js
and change code to:
Here I use a technique for routes called lazy loading. Basically, you need to create an array of router views (in my case routerOptions
) and then use map function over it to create routes. Then just pass them to router configuration object. And last thing is that I configured router to work in HTML5 history mode.
Another small but important code you need to add is in file App.vue
. Inside v-content
tag add:
<router-view></router-view>
This tag will tell Vue-router to render your routes inside it. If all code is correct you should see text Landing page
text instead of empty space. Next, you can try to type in localhost:8080/home
in address bar and you should see a text that you entered on corresponding Home.vue
template. This will mean that router is configured properly.
Adding menu
Typing localhost:8080/home
every time you want to change the page isn’t a case. Let’s add a menu.
All changes will be done in App.vue
, where our toolbar is. First add a new data property menuItems
:
<script>
export default {
data () {
return {
appTitle: 'Awesome App',
sidebar: false,
menuItems: [
{ title: 'Home', path: '/home', icon: 'home' },
{ title: 'Sign Up', path: '/signup', icon: 'face' },
{ title: 'Sign In', path: '/signin', icon: 'lock_open' }
]
}
}
}
</script>
Each item has a title, corresponding path and icon which we will use near the title (list of available icons is available here, by default Vuetify uses the material design iconset). I omitted root /
path in menuItems
because I want that my app title in toolbar lead me to this path. So let’s change it a bit:
<v-toolbar-title>
<router-link to="/" tag="span" style="cursor: pointer">
{{ appTitle }}
</router-link>
</v-toolbar-title>
Now our appTitle
is wrapped by router link. It points to /
, option tag="span"
will not change appearance of the title. cursor: pointer
style will change the cursor to pointer when you hover it over title.
It’s time to show our menu on the page. Add following code to navigation drawer:
<v-navigation-drawer v-model="sidebar">
<v-list>
<v-list-tile
v-for="item in menuItems"
:key="item.title"
:to="item.path">
<v-list-tile-action>
<v-icon>{{ item.icon }}</v-icon>
</v-list-tile-action>
<v-list-tile-content>{{ item.title }}</v-list-tile-content>
</v-list-tile>
</v-list>
</v-navigation-drawer>
Here I use v-for
directive for loop through my menuItems
and render them to a list. Each list tile has a unique key
attribute (I bind item.title
to it) because Vue.js requires it. Then I bind item.path
to router attribute to
in order this list item to be a link. Finally, I populate icon and title to corresponding tags.
Very similar code is for toolbar. Place following code right after v-spacer
tag:
<v-toolbar-items class="hidden-xs-only">
<v-btn
flat
v-for="item in menuItems"
:key="item.title"
:to="item.path">
<v-icon left dark>{{ item.icon }}</v-icon>
{{ item.title }}
</v-btn>
</v-toolbar-items>
Instead of list here I use Vuetify buttons v-btn
. The whole v-toolbar-items
will be hidden on xs
width devices.
Final code of App.vue
:
Check the menu now. You should be able to navigate to any path by clicking on links.
Adding content to pages
For now our pages don’t have any content except the pages name. Let’s fix this quickly.
First I will populate Landing.vue
that it looks more like real landing page:
Next will be Signup.vue
page:
The structure is simple. Here we have a three text fields with email, password and password confirmation. I omitted the functionality so far, will add it later.
Sign in page looks very similar to sign up. Here is code for Signin.vue
:
And finally home page. Very simple. Home.vue
:
Now with content it’s easier to define on which page you are.
State management with Vuex
Another big part of this application is a state management system. We will use Vuex for this purpose. I like this description of Vuex from official documentation:
It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion
Let’s install it first. Stop the current dev server if it still running with ctrl+c. Run:
npm install --save vuex# restart dev server again
npm run dev
Now we need to create a store. In /src
create a new folder /store
and index.js
file. Open index.js
and put there the following code:
This code is pretty straightforward. First we import Vue and Vuex, after that we tell Vue to use Vuex, and finally export our store. About store components.
state
is an object with application data. mutations
are needed to change that state. actions
are needed to dispatch mutations. And getters
are needed to get the store.
Finally, to use this store in our app we need to import it. Let’s add our store to main.js
:
Basically, we need to import our store (in the top). And then to pass it to our Vue instance (line 16).
Done! The store is ready to use. Let’s test it. Add a new variable to state
(file /store/index.js
):
You can use it in our App.vue
like this:
Here I first commented line with existing data property appTitle
and added computed property with corresponding name. It just return a state appTitle
from object $store
which is available globally in the app (thus we can access it by calling this.$store
). Now you should see “My Awesome App” title instead of just “Awesome App” in toolbar.
If you completed all the steps above you should get something like this:
Summary
Let’s stop here and wrap up what we have.
At this point we have very basic structure of our SPA. It has only four views but it’s enough to create a basic sign in and sign up functionality. Also following best practices we have central state management system. Now we are fully ready to proceed with adding Firebase and implementing authorization functionality. This will be covered in part 2.
Code for this part is available here:
https://github.com/oleg-agapov/basic-spa-vue-firebase/tree/part-1
If you like this tutorial you can donate me a few bucks💰 to my paypal account.
Special thanks to Peter Trotman who helped me with editing this article.