Welcome folks today in this blog post we will be building a socket.io
chat system in node.js and express using ejs
in browser using javascript. All the full source code of the application is shown below.
Get Started
In order to get started you need to make a new node.js
project using the below command as shown below
npm init -y
npm i express
npm i multer
npm i mongoose
npm i socket.io
And now you will see the below directory
structure of the node.js app as shown below
And now we need to make the index.js
file and copy paste the following code
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
const express = require("express"); const app = express(); const http = require("http").createServer(app); const io = require("socket.io")(http); const mongoose = require("mongoose"); const multer = require("multer"); const PORT = process.env.PORT || 3000; const MONGODB_URI = process.env.MONGODB_URI || "mongodb://localhost/chatapp"; mongoose .connect(MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => console.log("MongoDB connected")) .catch((err) => console.log(err)); const MessageSchema = new mongoose.Schema({ author: String, content: String, image: String, }); const Message = mongoose.model("Message", MessageSchema); app.use(express.static(__dirname + "/public")); app.get("/", (req, res) => { res.sendFile(__dirname + "/index.html"); }); const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, "public/uploads/"); }, filename: function (req, file, cb) { cb(null, Date.now() + "-" + file.originalname); }, }); const upload = multer({ storage: storage }); io.on("connection", (socket) => { console.log("A user connected"); socket.on("username", (username) => { socket.username = username; console.log("username is" + username); io.emit("user joined", username); }); Message.find({}) .then((messages) => { // Emit all messages to the new client socket.emit("load messages", messages); }) .catch((err) => { console.error(err); }); socket.on("chat message", (msg) => { console.log("message: " + msg); const message = new Message({ author: msg.author, content: msg.content, image: msg.image, }); message .save() .then(() => { io.emit("chat message", msg); }) .catch((err) => console.log(err)); }); socket.on("disconnect", () => { console.log("A user disconnected"); io.emit("user left", socket.username); }); }); http.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); }); |
As you can see we have started the express
app and then we have included the socket.io
library using the http
server. And then we have the different events
for the socket for example whenever the socket is connected and disconnected.
And now we need to make the public
folder and inside it we need to make the index.html
and also copy paste the following code
public/index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
<!DOCTYPE html> <html> <head> <title>Socket.IO Chat Example</title> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: Arial, sans-serif; } form { display: flex; margin-top: 10px; } form input[type="text"] { flex: 1; padding: 10px; } form input[type="file"] { margin-left: 10px; } form button { padding: 10px; background-color: #4caf50; color: #fff; border: none; } ul { list-style: none; padding: 0; margin-top: 10px; } li { margin-bottom: 5px; } .image { max-width: 100%; max-height: 300px; margin-top: 5px; } #chat { display: flex; margin: 0 auto; flex-direction: column; justify-content: space-between; width: 800px; height: 500px; border: 1px solid #ccc; border-radius: 5px; overflow: hidden; } #messages { list-style: none; margin: 0; padding: 10px; height: 80%; overflow-y: auto; } #chat-form { display: flex; justify-content: space-between; align-items: center; padding: 10px; background-color: #f9f9f9; border-top: 1px solid #ccc; } #message { flex-grow: 1; margin-right: 10px; padding: 10px; border: none; border-radius: 5px; font-size: 16px; } .chat-message { margin-bottom: 10px; border: none; border-bottom: 1px solid #dee2e6; padding: 5px 0; font-size: 16px; line-height: 1.5; } .chat-username { color: red; font-weight: bold; } </style> </head> <body> <br /> <h1 style="text-align: center">Public Chat Room</h1> <br /><br /> <div id="chat"> <ul id="messages"></ul> <form id="chat-form"> <input id="message" type="text" placeholder="Enter your message" /> <input type="file" accept="image/*" /> <button>Send</button> </form> </div> <script src="/socket.io/socket.io.js"></script> <script src="script.js"></script> </body> </html> |
As you can see we have the chat
div and inside it we have the text field where the user can enter the message
and then we have the input field where user can select the image and we have the send
message button. And now we need to make the script.js
file and copy paste the following code
script.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
const socket = io(); let username; if (localStorage.getItem("username")) { username = localStorage.getItem("username"); socket.emit("username", username); } else { Swal.fire({ title: "Enter your username", input: "text", inputLabel: "Username", inputPlaceholder: "Enter your username", allowOutsideClick: false, inputValidator: (value) => { if (!value) { return "You need to enter a username!"; } }, confirmButtonText: "Enter Chat", showLoaderOnConfirm: true, preConfirm: (username) => {}, }).then((result) => { console.log(result); username = result.value; socket.emit("username", username); localStorage.setItem("username", username); }); } function scrollToBottom() { const messageList = document.getElementById("messages"); console.log( `scrollTop: ${messageList.scrollTop}, scrollHeight: ${messageList.scrollHeight}` ); messageList.scrollTop = messageList.scrollHeight; console.log( `new scrollTop: ${messageList.scrollTop}, scrollHeight: ${messageList.scrollHeight}` ); } socket.on("user joined", (username) => { console.log(username); const item = document.createElement("li"); item.classList.add("chat-message"); item.innerHTML = `<span class="chat-username">${username}</span> : has joined the chat`; messages.appendChild(item); scrollToBottom(); }); socket.on("user left", (data) => { console.log(data); console.log("user left " + data); const item = document.createElement("li"); item.classList.add("chat-message"); item.innerHTML = `<span class="chat-username">${data}</span> : has left the chat`; messages.appendChild(item); scrollToBottom(); }); const form = document.getElementById("chat-form"); const input = form.querySelector('input[type="text"]'); const fileInput = form.querySelector('input[type="file"]'); const messages = document.getElementById("messages"); form.addEventListener("submit", (e) => { e.preventDefault(); const reader = new FileReader(); const file = fileInput.files[0]; if (!file && !input.value) { alert("Please enter the message"); return; } if (file) { reader.readAsDataURL(file); reader.onload = () => { socket.emit("chat message", { author: username, content: input.value, image: reader.result, }); input.value = ""; fileInput.value = ""; }; } else { socket.emit("chat message", { author: username, content: input.value, image: null, }); input.value = ""; } }); socket.on("chat message", (msg) => { const item = document.createElement("li"); item.classList.add("chat-message"); item.innerHTML = `<span class="chat-username">${msg.author}</span> : ${msg.content}`; //item.innerText = msg.author + ": " + msg.content; if (msg.image) { const img = document.createElement("img"); img.src = msg.image; img.classList.add("image"); item.appendChild(img); } messages.appendChild(item); scrollToBottom(); }); socket.on("load messages", (messages) => { const messageList = document.getElementById("messages"); messages.forEach((msg) => { const item = document.createElement("li"); item.classList.add("chat-message"); item.innerHTML = `<span class="chat-username">${msg.author}</span> : ${msg.content}`; //item.innerText = msg.author + ": " + msg.content; if (msg.image) { const img = document.createElement("img"); img.src = msg.image; img.classList.add("image"); item.appendChild(img); } messageList.appendChild(item); }); scrollToBottom(); }); |