Realtime Chat with ExpressJS and Socket.IO: A Practical Guide #
This tutorial will walk you through the process of building a basic realtime chat application using ExpressJS for the backend and Socket.IO to handle the realtime communication. This example provides a solid foundation for more complex chat applications.
Prerequisites #
Before we begin, ensure you have the following installed on your machine:
- Node.js and npm (Node Package Manager): You can download Node.js from the official website: https://nodejs.org/ NPM comes bundled with Node.js.
- A code editor: VS Code, Sublime Text, or any editor of your choice.
Setting Up the Project #
First, let’s create a new project directory and initialize a Node.js project.
-
Create a project directory:
mkdir express-chat cd express-chat
-
Initialize a new Node.js project:
npm init -y
This command creates a
package.json
file with default settings. -
Install required packages:
npm install express socket.io
This installs ExpressJS for our web server and Socket.IO for handling realtime communication.
Building the Server (ExpressJS and Socket.IO) #
Now, let’s create our server file (server.js
) and configure ExpressJS and Socket.IO.
// server.js
const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
const port = process.env.PORT || 3000;
// Serve static files (HTML, CSS, JS) from the 'public' directory
app.use(express.static('public'));
// Socket.IO logic
io.on('connection', (socket) => {
console.log('A user connected:', socket.id);
// Handle chat message event
socket.on('chat message', (msg) => {
console.log('Message received:', msg);
// Broadcast the message to all connected clients
io.emit('chat message', {
user: socket.id.substring(0, 5), // Shorten socket ID for display
message: msg,
});
});
// Handle disconnection
socket.on('disconnect', () => {
console.log('User disconnected:', socket.id);
});
});
server.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
Explanation:
- We import the necessary modules:
express
,http
, andsocket.io
. - We create an Express application (
app
) and an HTTP server (server
) usinghttp.createServer(app)
. Socket.IO needs the HTTP server. - We initialize Socket.IO by passing the HTTP server instance to it:
socketIO(server)
. - We define the port the server will listen on, defaulting to 3000 if the environment variable
PORT
is not set. app.use(express.static('public'))
tells Express to serve static files (like our HTML, CSS, and JavaScript) from a directory namedpublic
. We’ll create this directory later.io.on('connection', (socket) => { ... })
sets up a connection listener. This function is executed when a new client connects to the server. Each client gets its ownsocket
object.- Inside the connection handler:
console.log('A user connected:', socket.id)
logs the socket ID of the new client to the console.socket.on('chat message', (msg) => { ... })
listens for a custom event namedchat message
from the client. When a message is received, the callback function is executed.io.emit('chat message', { ... })
broadcasts the received message to all connected clients. Theio.emit
function sends a message to all connected sockets. We also include a shortened version of the user’s socket ID.socket.on('disconnect', () => { ... })
listens for adisconnect
event, which is triggered when a client disconnects.
Creating the Client-Side Interface (HTML, CSS, and JavaScript) #
Next, create a directory named public
in the root of your project:
mkdir public
cd public
Inside the public
directory, create the following files: index.html
, style.css
, and script.js
.
1. index.html
:
<!DOCTYPE html>
<html>
<head>
<title>Realtime Chat</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="chat-container">
<ul id="messages"></ul>
<form id="message-form" action="">
<input id="message-input" autocomplete="off" /><button>Send</button>
</form>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="script.js"></script>
</body>
</html>
Explanation:
- We include a basic HTML structure with a title and links to our CSS and JavaScript files.
- The
chat-container
div holds the chat interface elements. messages
is an unordered list that will display the chat messages.message-form
contains the input field (message-input
) and a submit button.<script src="/socket.io/socket.io.js"></script>
includes the Socket.IO client library. Crucially, the server automatically serves this at/socket.io/socket.io.js
.<script src="script.js"></script>
includes our custom JavaScript file.
2. style.css
:
body {
font-family: sans-serif;
margin: 0;
padding-bottom: 50px;
background-color: #f0f0f0;
}
#chat-container {
max-width: 600px;
margin: 20px auto;
background-color: #fff;
border-radius: 5px;
padding: 20px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
#messages {
list-style-type: none;
margin: 0;
padding: 0;
}
#messages li {
padding: 5px 10px;
}
#messages li:nth-child(odd) {
background: #eee;
}
#message-form {
background: #000;
padding: 3px;
position: fixed;
bottom: 0;
width: 100%;
max-width: 600px;
margin: 0 auto;
left: 0;
right: 0; /* Added to keep it centered */
}
#message-form input {
border: 0;
padding: 10px;
width: 90%;
margin-right: 0.5%;
}
#message-form button {
background: rgb(130, 224, 255);
border: none;
padding: 10px;
width: 9%;
}
This provides basic styling for our chat interface.
3. script.js
:
const socket = io(); // Connect to the Socket.IO server
const messages = document.getElementById('messages');
const form = document.getElementById('message-form');
const input = document.getElementById('message-input');
form.addEventListener('submit', (e) => {
e.preventDefault(); // Prevent form submission from reloading the page
if (input.value) {
socket.emit('chat message', input.value); // Send the message to the server
input.value = ''; // Clear the input field
}
});
socket.on('chat message', (data) => {
const item = document.createElement('li');
item.textContent = `${data.user}: ${data.message}`;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight); // Scroll to the bottom
});
Explanation:
const socket = io();
establishes a connection to the Socket.IO server running on the same host and port.- We get references to the HTML elements we need.
form.addEventListener('submit', (e) => { ... })
listens for the form submission event.- Inside the submit handler:
e.preventDefault();
prevents the default form submission behavior, which would reload the page.socket.emit('chat message', input.value);
sends a custom event namedchat message
to the server, along with the message text.input.value = '';
clears the input field.
socket.on('chat message', (data) => { ... })
listens for thechat message
event from the server.- Inside the message handler:
- We create a new
li
element and set its text content to the received message. - We append the new
li
element to themessages
list. - We scroll to the bottom of the page to keep the latest message visible.
- We create a new
Running the Application #
-
Save all files. Make sure
server.js
is in your project root andindex.html
,style.css
, andscript.js
are in thepublic
directory. -
Start the server:
node server.js
-
Open your browser and navigate to
http://localhost:3000
. -
Open multiple browser windows or tabs pointing to the same address. You should now be able to send messages from one window and see them appear in all the other windows in realtime.
Conclusion #
Congratulations! You have successfully built a simple realtime chat application using ExpressJS and Socket.IO. This tutorial provides a fundamental understanding of how to set up a basic chat application. You can expand upon this foundation by adding features such as user authentication, private messaging, room support, and more. Remember to explore the Socket.IO documentation for advanced features and options.