A deep dive into creating a real-time chat application using WebSockets in Node.js.

2024-12-14

Real-time applications like chat systems, collaborative tools, or live notifications require a different approach compared to traditional request-response web applications. In this article, we’ll explore how to build a real-time chat app using WebSockets and Node.js, step by step.

What Are WebSockets?

WebSockets provide a full-duplex communication channel over a single TCP connection. Unlike HTTP, where the client initiates a request and waits for a response, WebSockets enable a persistent connection that allows the server to send data to the client without being polled.

This makes WebSockets perfect for real-time applications where low latency is critical.

Setting Up the Project

Having Node.js installed let’s start by creating a new Node.js project.

1. Initialize the Project

Run the following commands to initialize a new Node.js project:

mkdir realtime-chat
cd realtime-chat
npm init -y

2. Install Dependencies

We’ll use the ws library, a lightweight WebSocket implementation for Node.js:

npm install ws express
  • ws: Provides WebSocket support.
  • express: Serves the frontend for our chat app.

3. Directory Structure

Create the following directory structure:

realtime-chat/
├── public/
│   ├── index.html
│   └── script.js
├── server.js
└── package.json

Building the Backend

In the server.js file, we’ll set up an Express server to serve our frontend and a WebSocket server for real-time communication.

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 });
 
// Serve static files from the public directory
app.use(express.static("public"));
 
// Handle WebSocket connections
wss.on("connection", (ws) => {
  console.log("A new client connected!");
 
  ws.on("message", (message) => {
    console.log(`Received: ${message}`);
 
    // Broadcast the message to all connected clients
    wss.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(message);
      }
    });
  });
 
  ws.on("close", () => {
    console.log("A client disconnected.");
  });
});
 
// Start the server
const PORT = 3000;
server.listen(PORT, () => {
  console.log(`Server is running on <http://localhost:${PORT}`);
});

Creating the Frontend

The frontend will be a simple HTML page with a basic chat interface.

public/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Real-Time Chat</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        margin: 0;
        padding: 0;
      }
      .chat {
        max-width: 600px;
        margin: 50px auto;
        border: 1px solid #ccc;
        padding: 20px;
        border-radius: 5px;
      }
      .messages {
        height: 300px;
        overflow-y: scroll;
        border: 1px solid #ccc;
        padding: 10px;
        margin-bottom: 20px;
      }
      .messages div {
        margin-bottom: 10px;
      }
      .input {
        display: flex;
      }
      .input input {
        flex: 1;
        padding: 10px;
        border: 1px solid #ccc;
        border-radius: 5px;
      }
      .input button {
        padding: 10px;
        border: none;
        background-color: #007bff;
        color: white;
        border-radius: 5px;
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div class="chat">
      <div class="messages" id="messages"></div>
      <div class="input">
        <input type="text" id="messageInput" placeholder="Type a message..." />
        <button id="sendButton">Send</button>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>

public/script.js

The frontend JavaScript will handle sending and receiving messages via the WebSocket connection.

const ws = new WebSocket("ws://localhost:3000");
 
const messagesDiv = document.getElementById("messages");
const messageInput = document.getElementById("messageInput");
const sendButton = document.getElementById("sendButton");
 
// Display incoming messages
ws.onmessage = (event) => {
  event.data.text().then((text) => {
    const message = document.createElement("div");
    message.textContent = text;
    messagesDiv.appendChild(message);
    messagesDiv.scrollTop = messagesDiv.scrollHeight;
  });
};
 
// Send a message when the button is clicked
sendButton.addEventListener("click", () => {
  const message = messageInput.value;
  ws.send(message);
  messageInput.value = "";
});
 
// Handle the Enter key
messageInput.addEventListener("keypress", (event) => {
  if (event.key === "Enter") {
    sendButton.click();
  }
});

Running the Application

  1. Start the server:

    node server.js
  2. Open http://localhost:3000 in your browser.

  3. Open multiple browser tabs and start chatting! Messages will appear in real time across all connected clients.

Next Steps

This is a basic real-time chat app to get you started with WebSockets. You can extend it further:

  • Add user authentication.
  • Store messages in a database.
  • Deploy the application to a cloud platform like Vercel or AWS.

WebSockets are a powerful tool for building real-time applications. With this foundational example, you’re ready to explore more complex use cases!