Building a simple real-time chat application using Socket.io, Express and Vue JS

Sanath Kumar
Jul 19, 2018 · 7 min read
Photo by Stanley Dai on Unsplash

Vue JS is awesome. Add socket.io to the mix and building powerful real-time Apps feels like a breeze. In this article let’s see how we can build a real-time group chat application using Express, Socket.io and Vue JS.

I will be providing complete codes at the end of this article which can be downloaded to your local development setup.

Let’s start by creating an Express server. Inside your project directory create a new project using the commands below.

mkdir socket-server
cd socket-server
npm init -y

Installing Express

Install express inside our NodeJS app using the following command.

npm install -- save express

Create an index.js file inside your project directory and add the following code inside to get your express server up and running.

const express = require(‘express’);
const app = new express();
app.listen(5000,() => {
console.log(“Howdy, I am running at PORT 5000”);
})

Installing Nodemon

Installing nodemon will ensure that you don’t have to restart your server every time you make changes to your codes. Let’s install nodemon as a development dependency using the following command.

npm install -- save-dev nodemon

Now inside your package.json file add the following line inside the scripts section.

"dev" : "nodemon index.js"

Finally, use the following command to run your server

npm run dev

We need a few other npm packages as well for our server app. They are socket.io, mongoose, body-parser and cors. Let’s install them using the following command.

npm install -- save socket.io body-parser mongoose cors

Let’s code

Create two folders named config and model inside your root directory. Create a new file keys.js inside the config folder and paste your Mongo DB url inside it as shown in the snippet below.

config/keys.js

Coding the Server

Create a new file named index.js inside your root directory and paste the following code inside it.

index.js

We have created a new socket.io instance attached to our express server, which listens to incoming messages. Every time a new chat is emitted by our Vue JS client the incoming message is saved to Mongo DB.

We have also written a chat API that returns all the saved chats in our chat collection. we are also using the cors package to enable all cors requests.

This is how the mongoose schema for our chat collection looks like.

models/message.js

Paste the above snippet inside modelmessage.js, and this pretty much sums up our server side code. Pretty simple right ?

Fire up your Express server using npm run dev. Now, we have the Express Server running at http://localhost:5000 with our socket.io instance listening to incoming connections and messages.

Coding the Client

Now let’s start building our front-end application. I bet it’s going to be fun as this is where all the real action happens.

Assuming you have Vue CLI installed in your computer, create a new Vue project inside your project directory with the following command.

vue init webpack-simple socket-client
cd socket-client
npm install

If you don’t have Vue installed in your development setup you can always install it using the npm package manager as follows

npm install -g vue-cli

Adding Vuetify

Vuetify is an elegant components framework developed for Vue JS. We will be using Vuetify to design the front-end of our application. In case you haven't used vuetify in the past don’t worry. You will have a pretty good understanding of how it works by the end of this article.

Let’s install vuetify

npm install -- save vuetify

Now, inside your main.js file add the following snippet to add Vuetify to your project.

import Vuetify from ‘vuetify’
Vue.use(Vuetify)
import ‘vuetify/dist/vuetify.min.css’

Now let’s add vuex, axios, moment and socket.io to our project

npm install — save vuex axios vue-moment vue-socket-io

We will use Axios to fetch the messages from the Chat API we have implemented. Also, we will be using moment to prettify the timestamps of each of our messages.

We will also be using the Vuex state extensively. If you are not familiar with Vuex, I would recommend reading my article on Mastering Vuex.

Setting up socket.io in Vue JS

Add the following snippet inside your main.js file to set up socket.io inside the Vue App

import VueSocketio from ‘vue-socket.io’
Vue.use(VueSocketio, ‘http://localhost:5000')

Setting up Vuex store

Create a new folder store inside your root directory and add a new index.js file inside it.

store/index.js

Create an empty store as shown in the snippet and add two items to the state

  1. chats
  2. handle
state : {
chats : null,
handle : “”
},

Import the store inside the main.js file and attach it to your Vue instance as follows.

import { store } from ‘./store’new Vue({
el: ‘#app’,
store,
render: h => h(App)
})

Notice how we have used ES6 to write just store rather than store : store.

This is how the final main.js file looks like

main.js

Now that all the boilerplate is out of our way let’s get our hands dirty and start building our app.

Basic overview of the App

Before we begin, I’ll give you a basic overview of the app we are developing. For the purpose of keeping this article as simple as possible we will not be adding any kind of authentication for the users of our app. Instead, each user will be uniquely identified by a handle of the users choice.

However, this design could be easily extended to support user authentication with minor changes to the code.

As a user loads our application, he/she will be asked to save a handle which will then be stored in our Vuex store. Once, a user logs in with the handle of his choice he can simply type in messages and hit ENTER to emit the chat to the server which will be saved in our collection and the server in return will emit the same message back to the client which will be intercepted by the socket listener on the client.

Confused ? Don’t worry. Once we start coding our components you will get the hang of it.

The components

We will have 3 components inside our App.

  1. The Chat Box
  2. The Chat Items
  3. And, The Handle Input

Let’s create those components now.

Create a new folder components inside the root directory of your project and add 3 files inside named ChatBox.vue, ChatItem.vue and Handle.vue

Handle.vue

The Handle Component

This component prompts the user to input a handle and save the handle inside our Vuex store. Paste the following code inside the handle.vue file.

components/Handle.vue

We have a card-view inside of which there is a Text Field and a Button. Upon clicking the button we are dispatching an action SET_HANDLE with the handle as payload, to save the user-input to our Vuex store.

Inside actions in our store create a new action SET_HANDLE as follows.

SET_HANDLE : (context,payload)=> {
context.commit(“SET_HANDLE”,payload);
}

Now, create a new mutation SET_HANDLE inside mutations to save the handle to the state.

SET_HANDLE : (state,payload) => {
state.handle = payload;
}

In case you are new to Vuex make it a practice to always use actions to commit a mutation even if no asynchronous operations are involved.

Now that we have saved the user handle to our state let’s code our chat box to emit the messages sent by our users to the server.

Inside ChatBox.vue add the following code.

components/ChatBox.vue

Let’s inspect whats going on in the code. We have a form with a text-field inside. Upon submission sendMessage() method is triggered, which emits the message to our server via sockets as follows:

let response = await this.$socket.emit(‘chat’,message);

Now, if you remember, we have setup a custom listener called chat in our socket.io instance inside our Express server in the last section. The express server intercepts our message saves it to the Database and emits the message back with a custom chat event back to the client.

Let’s get back to our App.vue file now and display the chat messages. We will also setup a custom listener to listen to chats emitted by the server.

This is how the completed code of our App.vue file looks like:

App.vue

In the code above, you can see that we have imported the three components we have created. Also, we have couple of getters CHATS, and HANDLE. You’ll see how they are defined in a minute.

In the mounted block we are dispatching an action SET_CHAT which fetches all the existing chats from the the API we have created in our express server and saves the chat to the state via mutation.

There is also a socket block which wraps all the codes connected to the socket.io client. The chat method listens to incoming emits from the server and dispatches an action ADD_CHAT which pushes the received message to the chat array in our state.

Let’s see how the complete store file looks like.

store/index.js

The User Interface

As the user loads the App handle is null in the state. Messages are displayed only if handle is not null and the handle component is displayed in the else block as shown in the code.

Once the user inputs a handle the Handle component is replaced by the messages block which loops thorough the messages and renders the third component ChatItem with the message as props.

Let’s see how the ChatItem component looks like.

components/ChatItem.vue

The ChatItem component has an isMyhandle method to differentiate incoming and outgoing chats and sets the color of the handle accordingly. Also, Vue moment is used to prettify the date which is displayed as a tool-tip on hover.

My original plan was to add a bonus section at the end of the article, with tips on how to extend the group chat application we developed in to a real time one-to-one chat app. But, I would rather publish it in a different article as this one’s already too long.

Find complete codes for the server and client below.

Sanath Kumar

Written by

Full-Stack web developer and AWS architect.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade