Building a Real-time Chat System with Node.js, and WebSockets: A Step-by-Step Guide
Tags: javascript, webdev, programming, tutorial
Published: 2023-10-12 12:03:41


## Table of Contents

- [Introduction](#introduction)
- [What is Node.js?](#what-is-nodejs)
- [WebSockets?](#websockets)
- [Setting up the Development Environment](#setting-up-the-development-environment)
- [Setting up the Node.js Server](#setting-up-the-nodejs-server)
- [Designing the Chat UI](#designing-the-chat-ui)
- [Implementing WebSocket Client](#implementing-websocket-client)
- [Running the Chat System](#running-the-chat-system)
- [Final Result](#final-result)
- [Conclusion](#conclusion)

---


## Introduction



Ah, real-time chat systems. The backbone of modern communication. But what makes them so speedy and reliable? It’s Node.js and Websockets, baby!

**Node.js** is a server-side JavaScript platform that helps build fast and scalable network applications. Meanwhile, **Websockets** is a protocol that allows for real-time communication between a client and server. Combine the two and you’ve got a recipe for a highly responsive chat system.

Building a chat system with Node.js and Websockets has its perks. For one, it can handle a large number of users with ease. Plus, it’s extremely reliable, so you don’t have to worry about messages getting lost in the ether.

So, why not build your own real-time chat system with Node.js and Websockets? It’s a fun project that’ll sharpen your skills and maybe even impress some friends. Plus, you can add your own personalized touches, like custom emojis or user authentication. Let’s get started!

---


## What is Node.js?



Node.js is an open-source, cross-platform JavaScript runtime environment that executes JavaScript code outside of a web browser. It allows developers to use JavaScript on the server-side and is particularly useful for building scalable network applications. 

Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. It is commonly used for building web servers, real-time applications, and APIs.

---

## WebSockets?



Websockets is a protocol that allows for a persistent, two-way connection between a client and a server. This protocol is useful for real-time applications where the client needs to receive updates from the server without constantly requesting updates.

WebSockets use a single TCP connection that remains open as long as the connection between the client and server is needed. This allows for much faster and more efficient communication compared to traditional HTTP requests.

WebSockets are supported by most modern web browsers and can be used with a variety of programming languages for both client-side and server-side development. Some popular implementations of Websockets include Socket.io, SignalR, and WAMP.

Overall, WebSockets provide a powerful and flexible way to enable real-time communication between web applications and servers.

---

## Setting up the Development Environment

To set up the development environment for creating a basic Express server, you need to follow these steps:

 1. Download and install [Node.js](https://nodejs.org/en/download) from the official website if you haven’t already.

 2. Open a new terminal or command prompt window and navigate to the directory where you want to create your server-side web application.

 3. Create a new directory for your application by running the command `mkdir node-chat-app` (You can replace “node-chat-app” with any name of your choice).

 4. Move into the newly created directory by running the command `cd node-chat-app`.

 5. Initialize a new Node.js project by running the command `npm init`. This will create a `package.json` file to store project dependencies and other relevant information.

 6. Install Express and ws(a Node.js WebSocket library) as a dependency by running the command `npm install express ws`.

Once you have completed these steps, you can proceed to create a new file named `server.js` in the root directory of your project and begin building your Express server.

---

## Setting up the Node.js Server



First things first, let’s create an entry point file for our Express server by running the command `touch server.js` or you can create new file using your IDE. This file will serve as the starting point for our application. Feel free to name it whatever you like, but for the sake of simplicity, we’ll stick with the conventional name server.js.

Inside the `server.js` file, we’ll start by importing the necessary modules and creating an instance of the Express application. This can be done as follows:

 1. **Requiring Modules:**

   

```javascript
 const express = require('express');
const http = require('http');
const WebSocket = require('ws');
```

Here, three modules are being imported:

* express: A popular web application framework for Node.js.

* http: A core Node.js module for creating HTTP servers and clients.

* ws: A third-party module for working with WebSockets in Node.js.

**2. Creating an Express Application:**

  

```javascript
const app = express();
```

This initializes a new instance of an Express application. This application can be used to define routes, middleware, and other server-related configurations.

**3. Creating an HTTP Server:**

```javascript
const server = http.createServer(app);

```
Here, an HTTP server is being created using the http module. The app (Express application) is passed as a request listener to the server. This means that when the server receives an HTTP request, it will be handled by the Express application.

**4. Setting up a WebSocket Server:**

```javascript
const wss = new WebSocket.Server({ server });
```
This initializes a new instance of a WebSocket server using the ws module. The WebSocket server is bound to the previously created HTTP server (`server`). This means that the WebSocket server will share the same underlying TCP/IP port as the HTTP server. This is a common pattern because it allows you to serve regular HTTP(S) content and WebSocket content over the same port, which can simplify deployment and firewall configurations.

**5. Handling WebSocket Connections and Incoming Messages:**

```javascript
wss.on('connection', (ws) => {
    ws.on('message', (message) => {
        wss.clients.forEach((client) => {
            if (client !== ws && client.readyState === WebSocket.OPEN) {
                client.send(message);
            }
        });
    });
});
```

The `wss.on('connection', ...)` is an event listener that listens for new WebSocket connections. When a client connects to the WebSocket server, the callback function is executed with the connected WebSocket (ws) as its argument.

Inside the connection callback, there’s another event listener for the `message` event on the connected WebSocket (`ws`). This listener is triggered whenever the server receives a message from the connected client. The received message is passed to the callback as the message argument.

Within the message event callback, the code iterates over all connected WebSocket clients using `wss.clients.forEach(...)`. For each client:

* It checks if the client is not the one who sent the original message (`client !== ws`). This prevents echoing the message back to the sender.

* It checks if the client’s connection is still open (`client.readyState === WebSocket.OPEN`).

* If both conditions are met, it sends the received message to the client using `client.send(message)`. This effectively broadcasts the message to all other connected clients.

**6. Starting the HTTP Server:**

```javascript
server.listen(3000, () => {
  console.log('Server started on http://localhost:3000');
});
```

This code starts the HTTP server on port 3000. Once the server is successfully started, the callback function is executed, logging the message “Server started on [http://localhost:3000](http://localhost:3000/)" to the console. This provides feedback that the server is running and listening for incoming connections on the specified port.

**7. Complete code of `server.js` file**

```javascript
const express = require('express');
const http = require('http');
const WebSocket = require('ws');

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

wss.on('connection', (ws) => {
    ws.on('message', (message) => {
        wss.clients.forEach((client) => {
            if (client !== ws && client.readyState === WebSocket.OPEN) {
                client.send(message);
            }
        });
    });
});

server.listen(3000, () => {
    console.log('Server started on http://localhost:3000');
});
```

---

## Designing the Chat UI



Create a `public` folder and inside it, create `index.html` and style.css\

**In index.html:**

    

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Bot Chat</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
<div class="chat-container">
    <div class="messages"></div>
    <div class="chat-box">
        <div class="messages"></div>
        <div class="input-container">
            <input type="text" class="message-input" placeholder="Type a message...">
            <button class="send-btn">Send Message</button>
        </div>
    </div>
</div>
<script src="script.js"></script>
</body>
</html>
```

**In `style.css`:**

    

```css
body {
    font-family: 'Arial', sans-serif;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: #f4f4f4;
}

.chat-container {
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    background-color: #fff;
    border-radius: 5px;
    overflow: hidden;
}

.chat-box {
    width: 400px;
    height: 500px;
    display: flex;
    flex-direction: column;
}

.messages {
    flex: 1;
    padding: 20px;
    overflow-y: auto;
}

.input-container {
    display: flex;
    align-items: center;
    padding: 10px;
    border-top: 1px solid #e0e0e0;
}

.message-input {
    flex: 1;
    padding: 10px;
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    margin-right: 10px;
}
.send-btn {
    padding: 10px 20px;
    background-color: #007BFF;
    color: #fff;
    border: none;
    cursor: pointer;
    transition: background-color 0.3s;
}

.send-btn:hover {
    background-color: #0056b3;
}
```

---

## Implementing WebSocket Client



Create a `script.js` file inside the `public` folder:

 

```javascript
const messagesDiv = document.querySelector('.messages');
const sendBtn = document.querySelector('.send-btn');
const messageInput = document.querySelector('.message-input');

const ws = new WebSocket('ws://localhost:3000');

ws.onopen = () => {
    console.log('Connected to the server');
};

ws.onmessage = (event) => {
    if (event.data instanceof Blob) {
        // Convert Blob to string
        const reader = new FileReader();
        reader.onload = function() {
            const text = reader.result;
            displayMessage(text);
        };
        reader.readAsText(event.data);
    } else {
        displayMessage(event.data);
    }
};
function displayMessage(message) {
    const msgDiv = document.createElement('div');
    msgDiv.textContent = `Other user: ${message}`;
    messagesDiv.appendChild(msgDiv);
}

sendBtn.addEventListener('click', () => {
    const message = messageInput.value;
    if (message.trim() === "") return; // Don't send empty messages

    ws.send(message);
    const msgDiv = document.createElement('div');
    msgDiv.textContent = `You: ${message}`;
    messagesDiv.appendChild(msgDiv);

    messageInput.value = ''; // Clear the input after sending
});
```

Here’s a breakdown of what each part of the code does:

 1. **DOM Element Selection:**

    

```javascript
const messagesDiv = document.querySelector('.messages');
const sendBtn = document.querySelector('.send-btn');
const messageInput = document.querySelector('.message-input');
```

These lines select three elements from the DOM:

* `messagesDiv`: A container where chat messages will be displayed.

* `sendBtn`: A button that users can click to send messages.

* `messageInput`: An input field where users can type their messages.

**2. WebSocket Initialization:**

```javascript
const ws = new WebSocket('ws://localhost:3000');

```
This line initializes a new WebSocket connection to the server located at `ws://localhost:3000`.

**3. WebSocket Event Handlers:**

onopen:

   

```javascript
ws.onopen = () => {
  console.log('Connected to the server');
};
```

This function is called when the WebSocket connection is successfully established. It logs a message to the console indicating that the connection has been made.

onmessage:

```javascript
ws.onmessage = (event) => {
    if (event.data instanceof Blob) {
        // Convert Blob to string
        const reader = new FileReader();
        reader.onload = function() {
            const text = reader.result;
            displayMessage(text);
        };
        reader.readAsText(event.data);
    } else {
        displayMessage(event.data);
    }
};
```

This function is called whenever a message is received from the server. If the received data is a `Blob` (binary large object, often used for representing file-like objects), it converts the blob to a string using the `FileReader` API. Otherwise, it directly displays the message.

**4. Display Message Function:**

```javascript
function displayMessage(message) {
    const msgDiv = document.createElement('div');
    msgDiv.textContent = `Other user: ${message}`;
    messagesDiv.appendChild(msgDiv);
}
```

This function creates a new `div` element, sets its content to the received message prefixed by "Other user:", and appends it to the `messagesDiv`.

**5. Send Button Event Listener:**

```javascript
sendBtn.addEventListener('click', () => {
    const message = messageInput.value;
    if (message.trim() === "") return; // Don't send empty messages

    ws.send(message);
    const msgDiv = document.createElement('div');
    msgDiv.textContent = `You: ${message}`;
    messagesDiv.appendChild(msgDiv);

    messageInput.value = ''; // Clear the input after sending
});
```

This code adds an event listener to the `sendBtn`. When the button is clicked:

* It retrieves the message from the `messageInput`.

* If the message is empty (after trimming whitespace), it returns without doing anything.

* Otherwise, it sends the message to the server using the WebSocket connection.

* It then creates a new `div` element, sets its content to the sent message prefixed by "You:", and appends it to the `messagesDiv`.

* Finally, it clears the `messageInput` to prepare for the next message.



Serve the `public` folder using Express in `server.js` by adding the following line to the `serve.js` file

```javascript
app.use(express.static('public'));
```
---

## Running the Chat System



Start the server:

```javascript
node server.js
```
Open `http://localhost:3000` in two different browser windows. Enter the message and click the "Send Message" button in one window, and you should see the message appear in both windows.

---

## Final Result

{% embed https://youtu.be/jzD1Tj41jos
 %}

---

## Conclusion



Congratulations! You have successfully built a real-time chat system with Node.js and Websockets. Let’s summarize the key steps we covered in this guide. We started with setting up the development environment by installing Node.js and Websockets. Then we built the back-end using Express.js and integrated Websockets with the server to handle user connections, disconnections, and messages.

After building the front-end with HTML and CSS, we tested the application locally and deployed it to a server.

Node.js and Websockets offer many benefits for real-time chat systems. They provide fast and seamless communication, real-time updates, and efficient resource utilization. With their lightweight and scalable architecture, they can handle thousands of connections simultaneously. 

The possibilities for future enhancements are endless. You can add more advanced features like real-time translation, voice and video chat, and AI-powered chatbots. The chat system you built here is just the starting point for an incredible chat experience.



**Source Code: [click here](https://drive.google.com/file/d/1R-J_yePidtdzfExUwPBubNVXokE7qyx7/view?usp=drive_link)**



### 🔗 Connect with me on:

* [🐙 Github](https://github.com/jaimaldullat)

* [📸 Instagram](https://instagram.com/codingwithjd)

### Thank you for joining me on this journey through my blog!

* **Follow:** Stay updated with the latest posts by hitting that follow button.

* **React:** Show your appreciation with a like/other reactions if you enjoyed the article.

* **Comment:** Engage in the conversation by leaving your thoughts, feedback, and questions.

* **Share:** Spread the word by sharing the blog post on your social media platforms or with friends and colleagues.