This content originally appeared on Bits and Pieces - Medium and was authored by Thomas Sentre
How to Create an RTC App with WebSockets and Node.js
Modern web applications often require some form of real-time communication, where data can continuous flow from client to server and vice-versa with minimal delay.
To fulfil this requirement, the HTML5 WebSocket Protocol was created. So, we can exchange messages, information in real-time.
In this post, we will focus on learning how to build a very basic real-time web application using WebSocket.
Implementing the Server
Let us get started with the server code. First, open a new terminal and create a folder named chat-app in the root directory. Dive to this folder and initialize the project by entering npm init or yarn init command in the terminal. Now that we initialized our app, let us know a bit more about WebSocket.
The WebSocket specification defines an API establishing “socket” connections between a web browser and a server. In plain words: With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply.
We will use WebSocket API to implement the real-time capabilities of our chat application. We will rely on its library called ws which is a pure WebSocket implementation for Node.js.
Ws is pretty simple to use, blazing fast and the code we are going to write will confirm this assumption. So, let’s create the server-side of our chat application in a file called index.js
chat-app/index.js
import { createServer } from 'http';
import staticHandler from 'serve-handler';
import ws, { WebSocketServer } from 'ws';
//serve static folder
const server=createServer((req,res)=>{ // (1)
return staticHandler(req,res,{public: 'public'})
});
const wss=new WebSocketServer({server}) // (2)
wss.on('connection',(client)=>{
console.log('Client connected !')
client.on('message',(msg)=>{ // (3)
console.log(`Message:${msg}`);
broadcast(msg)
})
})
function broadcast(msg) { // (4)
for(const client of wss.clients){
if(client.readyState === ws.OPEN){
client.send(msg)
}
}
}
server.listen(process.argv[2] || 8080,()=>{
console.log(`server listening...`);
})
That’s it! That’s all we need to implement the server-side component of our chat application. This is how it works:
- We first create an HTTP server and forward every request to a special handler which will take care to serve all the static files from the public directory. This is needed to access the client-side resources of our application (for example, HTML, JavaScript, and CSS files).
2. We then create a new instance of the WebSocket server, and we attach it to our existing HTTP server. Next, we start listening for incoming WebSocket client connections by attaching an event listener for the connection event.
3. Each time a new client connects to our server, we start listening for incoming messages. When a new message arrives, we broadcast it to all the connected clients.
4. The broadcast() function is a simple iteration over all the known clients, where the send() function is invoked on each connected client. This is the magic of Node.js! Of course, the server that we just implemented is very minimal and basic, but as we will see, it does its job.
Implementing the Client
Next, it’s time to implement the client-side of our chat application. This can be done with another compact and simple fragment of code, essentially a minimal HTML page with some basic JavaScript code. Let’s create this page in a file named public/index.html as follows:
chat-app/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="index.css">
<title>Minimlist chat App</title>
</head>
<body>
<div class="container">
<p class="msg">Messages:</p>
<div id="messages" class="messages"></div>
<form id="msgForm" class="msgForm">
<input type="text" placeholder="Send message" class="input" id="inputBox"/>
<input type="submit" class="btn" value="Send">
</form>
</div>
<script type="text/javascript">
const ws=new WebSocket(`ws://${window.document.location.host}`);
ws.binaryType = "blob";
// Log socket opening and closing
ws.addEventListener("open", event => {
console.log("Websocket connection opened");
});
ws.addEventListener("close", event => {
console.log("Websocket connection closed");
});
ws.onmessage = function(message){
const msgDiv=document.createElement('div');
msgDiv.classList.add('msgCtn');
if (message.data instanceof Blob) {
reader = new FileReader();
reader.onload = () => {
msgDiv.innerHTML = reader.result;
document.getElementById('messages').appendChild(msgDiv);
};
reader.readAsText(message.data);
} else {
console.log("Result2: " + message.data);
msgDiv.innerHTML = message.data;
document.getElementById('messages').appendChild(msgDiv);
}
}
const form=document.getElementById('msgForm');
form.addEventListener('submit',(event) => {
event.preventDefault();
const message=document.getElementById('inputBox').value;
ws.send(message);
document.getElementById('inputBox').value=''
})
</script>
</body>
</html>
Let’s add some styles to a file called index.css in the public directory to make our app look better.
chat-app/index.css
html{
font-size: 62.5%;
}
body{
margin:0;
padding: 0;
display:flex;
justify-content:center;
}
.container{
margin-top: 5rem;
display:flex;
flex-direction:column;
width: 30%;
height: 70vh;
}
.msg{
color:blueviolet;
font-size: 2rem;
}
.msgCtn{
margin: 1rem 0;
color: white;
padding: 1rem 1rem;
background-color: blueviolet;
border-radius: 6px;
font-size: 2rem
}
.msgForm{
display:flex;
flex-direction:row;
}
.input{
height: 100%;
flex: 4;
margin-right: 2rem;
border:none;
border-radius: .5rem;
padding: 2px 1rem;
font-size: 1.5rem;
background-color:aliceblue;
}
.input:focus{
background-color:white;
}
.btn{
height:5rem;
flex: 1;
display:flex;
justify-content:center;
align-items:center;
border-radius: .5rem;
background-color:blueviolet;
color: whitesmoke;
border:none;
font-size: 1.6rem;
}
The HTML page we just created doesn’t really need many comments, it’s just a piece of straightforward web development.
We use the native WebSocket object to initialize a connection to our Node.js server, and then start listening for messages from the server, displaying them in new div elements as they arrive.
The messages received from the server is binary data, so we use JavaScript Object called FileReader to read the contents of this data (or raw data buffers).
For sending messages, instead, we use a simple textbox and a button within a form.
Running the Application
We can try to run our application immediately. Just launch the server with the following command:
node index.js 8080
Then, open a couple of browser tabs or even two different browsers, point them at http://localhost:8080, and start chatting:
Now, we want to see what happens when we try to scale our application by launching multiple instances. Let’s try to do that. Let’s start another server on another port:
node index.js 8081
The desired outcome should be that two different clients, connected to two different servers, should be able to exchange chat messages. Unfortunately, this is not what happens with our current implementation. We can test this by opening another browser tab to http://localhost:8081.
When sending a chat message on one instance, we only broadcast the message locally, distributing it only to the clients connected to that particular server. In practice, the two servers are not talking to each other. We need to integrate them. To do that we need to use a message broker like RabbitMQ or Redis.
Conclusion
In this post, we have created a simple but functional chat app. You can find the complete source code for this application in this repository. I hope you have found this useful for getting up and running. Now you can decide to add more features as you see fit. What features would you like to see? Let us know in the comments!
Build component-driven. It’s better, faster, and more scalable.
Forget about monolithic apps, start building component-driven software. Build better software from independent components and compose them into infinite features and apps.
OSS Tools like Bit offer a great developer experience for building component-driven. Start small and scale with many apps, design systems or even Micro Frontends. Give it a try →
An independent product component: watch the auto-generated dependency graph
Build a Real-Time Chat App using Node.js and WebSocket was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Bits and Pieces - Medium and was authored by Thomas Sentre
Thomas Sentre | Sciencx (2022-02-16T11:38:32+00:00) Build a Real-Time Chat App using Node.js and WebSocket. Retrieved from https://www.scien.cx/2022/02/16/build-a-real-time-chat-app-using-node-js-and-websocket/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.