Build a Real-time Chat App with Vue 3, Socket.io and Nodejs

  • Build a Real-time Chat App with Vue 3, Socket.io and Nodejs

    Sharing is Caring... Show some love :)

    Real-time Chat App with Vue 3 Socket.io and Nodejs follows the previous article I wrote on how to build a real-time chat app with Vuejs, Socket.io, and Nodejs to demonstrate everything you need to set up and create your chat application with Vuejs.

    We are going to drive more insight from there to develop a more robust, secure, and advanced Real-time Chat App with Vue 3 Socket.io and Nodejs.

    Vue 3 is the most recent version of Vue.js which uses the new composition API, we are going to learn how to set it up and create our first real-time application with Vue 3.

    Also, we are going to learn more advanced and real-world concepts of a chat application including features such as authentication and authorization, setting up and storing messages to the database for further analysis.

    In this article, we are going to explore in-depth how to build a Real-time Chat App with Vue 3 Socket.io and Nodejs, we’ll also be learning how to add authentication and authorization to our chat application.

    Also, we will explore the process of storing and retrieving new and old chat messages from the database in our chat app in real-time.

    If this is what you’re looking to achieve, let’s jump in:

    Before you dive in, if you’re a backend developer or looking at delving into this career path, join other developers to receive daily articles on backend development that will boost your productivity.

    Here is a video of what we will be building.

    Build A Real-time Chat App

    Setup

    Before we get started, we need to make sure that we have the necessary tools installed to get started.

    Node.js and NPM are required for this tutorial and it can be easily installed from the official website.

    You will also need to have a little knowledge of JavaScript and Vuejs, you can learn VueJS by taking this course and JavaScript with this course also.

    If everything is set up properly, let’s get started:

    First, create a directory for the application and open the directory with your favorite text editor.

    mkdir advanced-chat-app && cd advanced-chat-app && code .

    Next, we will initialize the directory with NPM and install the necessary packages needed to build out our real-time chat application.

    Run the following command to initialize the project, open your terminal in the project root directory and run:

    npm init -y

    This will initialize the project with the default NPM set up and create the package.json file so we can start installing our packages.

    Dependency Installations

    Next, we will start installing our dependencies and setting them up, you can read more about each of the dependencies from the link provided.

    ALSO READ  Why learn vuejs as a backend developer

    First, we will install Express.js and Socket.io using the below command:

    npm install express socket.io --save

    Lastly, we will install other necessary dependencies (MySQL) using the below command.

    npm install mysql2 --save

    Database Setup

    Persisting the messages of our real-time chat is an added feature to our previous version of this article.

    Let’s look at how we can set up our database and start storing and retrieving messages from our database.

    First, create a database.js file:

    touch database.js

    and paste in the following codes:

    const mysql = require("mysql2");
    let db = null;
    class DB {
      constructor() {
        db = mysql.createConnection({
          host: "localhost",
          user: "root",
          password: "DB_PASSWORD",
          database: "advanced-chat-app",
        });
        db.connect(function (err) {
          if (err) console.log(err);
        });
      }
    
      addUser(data) {
        return new Promise(async (resolve, reject) => {
          if (await this.isUserExist(data)) {
            resolve("User already exist");
          } else
            db.execute(
              "INSERT INTO users (name, user_id) VALUES (?,?)",
              [data.name, data.user_id],
              function (err, rows) {
                if (err) reject(new Error(err));
                else resolve(rows);
              }
            );
        });
      }
    
      isUserExist(data) {
        return new Promise((resolve, reject) => {
          db.execute(
            "SELECT * FROM users WHERE name = ?",
            [data.name],
            function (err, rows) {
              if (err) reject(new Error(err));
              else resolve(rows[0]);
            }
          );
        });
      }
    
      fetchUserMessages(data) {
        const messages = [];
        return new Promise((resolve, reject) => {
          db.query(
            "SELECT * from messages where name =?",
            [data.name],
            function (err, rows) {
              if (err) reject(err);
              else resolve(rows);
            }
          );
    
        });
      }
    
      storeUserMessage(data) {
        return new Promise((resolve, reject) => {
          db.query(
            "INSERT INTO messages (message, user_id, name) VALUES (?,?,?)",
            [data.message, data.user_id, data.name],
            function (err, rows) {
              if (err) reject(new Error(err));
              else resolve(rows);
            }
          );
        });
      }
    }
    
    module.exports = DB;
    

    Server Setup

    Now we have our database configuration out of the way, we will set up our Node.js server with express and import our Database module to be used within the events.

    Let’s look at how to achieve this:

    First, create a server.js file within the directory:

    touch server.js

    and paste in the following codes.

    const app = require("express")();
    const http = require("http").Server(app);
    const io = require("socket.io")(http);
    const path = require("path");
    const DataBase = require("./database.js");
    
    const db = new DataBase();
    
    app.get("/", (req, res) => {
      res.sendFile(__dirname + "/index.html");
    });
    io.on("connection", function (socket) {
    
      console.log("A user with ID: " + socket.id + " connected");
    
      socket.on("disconnect", function () {
        console.log("A user with ID: " + socket.id + " disconnected");
      });
    
      // More Socket listening here.
      // if (io.sockets.connected) console.log(io.sockets.connected);
      // socket.emit("connections", Object.keys(io.sockets.connected).length);
    
      socket.on("chat-message", async (message) => {
        const data = {
          message: message.message,
          user_id: socket.id,
          name: message.user,
        };
        const messageData = await db.storeUserMessage(data);
        socket.broadcast.emit("chat-message", message);
      });
    
      socket.on("typing", (data) => {
        socket.broadcast.emit("typing", data);
      });
    
      socket.on("stopTyping", () => {
        socket.broadcast.emit("stopTyping");
      });
    
      socket.on("joined", async (name) => {
        let messageData = null;
        const data = {
          name,
          user_id: socket.id,
        };
        const user = await db.addUser(data);
        if (user === "User already exist") {
          messageData = await db.fetchUserMessages(data);
        }
        socket.broadcast.emit("joined", messageData);
      });
    
      socket.on("leave", (data) => {
        socket.broadcast.emit("leave", data);
      });
    
    });
    
    http.listen(3000, () => {
      console.log("Listening on port *: 3000");
    });

    So far, we have created our server using express’ HTTP Server and also initialized our Socket.io using the server instance we created.

    ALSO READ  Whats New in Electronjs with Nodejs

    We have also set up our homepage endpoint / to display our chat frontend design so we can interact with it.

    Next, we created our Socket.io connection and start listening for incoming requests/events e.g. the disconnect event.

    We have also made different calls to our databases where needed to either display or store messages in the database.

    Lastly, we created the server and listen to incoming requests using port 3000 on localhost.

    In my previous article, I explained vividly how socket.io works and the meaning of each method and events we will be using in this tutorial, you should be reading it now if you haven’t already.

    Now that we have the server part out of the way, let’s work on our frontend Vue 3 part:

    Take a break and subscribe to receive daily information that will boost your productivity as a Nodejs Backend Developer.

    Setting up Vue 3 Frontend

    Next, we will set up the frontend part of our real time chat app using Vue 3 and Bootstrap.

    Vue3 is very easy to get started by adding the CDN to our HTML file for development only:

    touch index.html

    Open the index.html file and add the following codes:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <link rel="icon" href="/favicon.ico" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>ChatApp_Socket</title>
      <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
    </head>
    <body>
      <div id="app">
          // Component Code added here
      </div>
    </body>
    </html>

    The code above just includes Bootstrap and Socket.io Client to the frontend.

    You can download the client-side Socket.IO library here as well.

    Next, we will add the following HTML codes inside <div id="app"> we created above:

    <div class="container">
            <div class="col-lg-6 offset-lg-3">
              <div v-if="ready">
                <p v-for="(user, i) in info" :key="i">
                  {{ user.username }} {{ user.type }}
                </p>
              </div>
        
              <div v-if="!ready">
                <h4>Enter your username</h4>
                <form @submit.prevent="addUser">
                  <div class="form-group row">
                    <input
                      type="text"
                      class="form-control col-9"
                      v-model="username"
                      placeholder="Enter username here"
                    />
                    <input
                      type="submit"
                      value="Join"
                      class="btn btn-sm btn-info ml-1"
                    />
                  </div>
                </form>
              </div>
              <h2 v-else>{{ username }}</h2>
              <div class="card bg-info" v-if="ready">
                <div class="card-header text-white">
                  <h4>
                    My Chat App
                    <span class="float-right">{{ connections }} connections</span>
                  </h4>
                </div>
                <ul class="list-group list-group-flush text-right">
                  <small v-if="typing" class="text-white">{{ typing }} is typing</small>
                  <li class="list-group-item" v-for="(message, i) in messages" :key="i">
                    <span :class="{ 'float-left': message.type === 1 }">
                      {{ message.message }}
                      <small>:{{ message.user }}</small>
                    </span>
                  </li>
                </ul>
        
                <div class="card-body">
                  <form @submit.prevent="send">
                    <div class="form-group">
                      <input
                        type="text"
                        class="form-control"
                        v-model="newMessage"
                        placeholder="Enter message here"
                      />
                    </div>
                  </form>
                </div>
              </div>
            </div>
          </div>

    Socket.io Events

    Next, we will create the different events to form our basis of communication with the server. The code will go under the comment in the script above.

      <script src="/socket.io/socket.io.js"></script>
      <script src="https://unpkg.com/[email protected]"></script>
      <script>
        const socket = io();
       const Chat =  {
          name: "Chat",
        
          data() {
            return {
              newMessage: null,
              messages: [],
              typing: false,
              username: null,
              ready: false,
              info: [],
              connections: 0,
            };
          },
          created() {
            window.onbeforeunload = () => {
              socket.emit("leave", this.username);
            };
        
            socket.on("chat-message", (data) => {
              this.messages.push({
                message: data.message,
                type: 1,
                user: data.user,
              });
            });
        
            socket.on("typing", (data) => {
              this.typing = data;
            });
        
            socket.on("stopTyping", () => {
              this.typing = false;
            });
        
            socket.on("joined", (data) => {
              this.info.push({
                username: data,
                type: "joined",
              });
        
              setTimeout(() => {
                this.info = [];
              }, 5000);
            });
            // data.forEach(element => {
            //     this.messages.push({
            //       message: element.message,
            //       type: 1,
            //       user: element.name,
            //     });
            //     this.info.push({
            //       username: element.name,
            //       type: "joined",
            //     });
            //   });
        
            socket.on("leave", (data) => {
              this.info.push({
                username: data,
                type: "left",
              });
        
              setTimeout(() => {
                this.info = [];
              }, 5000);
            });
        
            socket.on("connections", (data) => {
              this.connections = data;
            });
          },
        
          methods: {
            send() {
              this.messages.push({
                message: this.newMessage,
                type: 0,
                user: "Me",
              });
        
              socket.emit("chat-message", {
                message: this.newMessage,
                user: this.username,
              });
              this.newMessage = null;
            },
        
            addUser() {
              this.ready = true;
              socket.emit("joined", this.username);
            },
          },
        
          watch: {
            newMessage(value) {
              value ? socket.emit("typing", this.username) : socket.emit("stopTyping");
            },
          },
        };
    
        Vue.createApp(Chat).mount('#app');
      </script>
    </body>
    </html>

    The above script uses the on method of the Socket.io to listen for different events from the server and also wait for responses from the server.

    ALSO READ  Build a real-time chat app with Vuejs, socket.IO, and Nodejs

    Also, the emit method of the Socket.io is used to dispatch or emit events to the server like the POST method in Restful API.

    In the same spirit, we listened to different events such as typing, joined, stopTyping etc and response respectively to the different events.

    There is a lot happening in that script above, which was explained in my previous article, you should definitely check it out before reading this one.

    But here, we will give you a little context of what is happening:

    In Vue methods, we have created two methods send() and addUser() methods which basically sends messages to the user using the emit method of the Socket.io and addUser emits the joined event to add that specific user to the chat.

    Conclusion

    We have learned a lot with build a real-time chat app with Vuejs, socket.io, and Nodejs article.

    Also, we have learned how to add authentications and add database management to manage all your new changes.

    I hope you learned something new with Vue, Node, Express, and Socket.IO. The full code is on GitHub, get it now.

    Thank you for reading my article.

    Here at my blog or medium I regularly write about backend development, digital marketing, and content management system. To read my future posts simply join my publication or click ‘Follow’ Also feel free to connect with me via Twitter, Facebook, Instagram.

    If you enjoy this post, make sure to let us know and share it with your friends.

    Start Learning Backend Dev. Now

    Stop waiting and start learning! Get my 10 tips on teaching yourself backend development.

    Don't worry. I'll never, ever spam you!

    Sharing is caring :)

    Start Learning Now
    Learning for all. Savings for you. Courses from $11.99

    Comments

    Newsletter

    Get the latest Backend Dev. jobs, events and curated articles straight to your inbox, once a week

    Start Learning Now
    Learning for all. Savings for you. Courses from $11.99
    Top 6 Recent Posts
    Start Learning Now
    Learning for all. Savings for you. Courses from $11.99