Simple Chat with Node.js + WebSockets

One of the best use cases for Node.js is real-time applications that handle lots of small requests simultaneously. A perfect example of this is a small chat application that allows multiple users to connect and send messages to each other. So today we are going to build this.

We are going to be utilizing a technology called WebSockets, which will allow us to communicate between all of the users of our application quickly. We are using WebSockets via a Node module called Socket.IO. However, before we can dig into all the communications, we are going to need some Node code.

For static content, we are using Express. Maybe a little overkill, but it does the job. The base app.js file will look like so:

var express = require('express');
var app = express();
var server = require('http').createServer(app);

server.listen(80);
app.use("/", express.static(__dirname + '/public'));

Nothing special. What we need now though is some Socket.IO action. We need to accept an incoming message then blast it out to everyone else that is listening to our server. Thankfully it is a small tweak on the server-side:

var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);

server.listen(80);

app.use("/", express.static(__dirname + '/public'));

io.sockets.on('connection', function (socket) {
  socket.on('msg', function (data) {
    io.sockets.emit('new', data);
  });
});

Yeap, a require statement and two callbacks later we have our server-side code. Basically what this is doing is waiting for a connection, then when a connection is established, it subscribes to the “msg” event that happens when a client sends a message to the server. When this happens, we send the message to all connected clients, or “sockets” as they are called in this case — simple stuff.

The client is a bit more complicated though. Let’s start with the HTML, which is pretty straight-forward.

<!DOCTYPE HTML>
 <html>
 <head>
  <title>Simple Chat</title>
  <script type="text/javascript" src="/socket.io/socket.io.js"></script>
  <script 
    type="text/javascript"
    src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
 </head>
 <body>
  <div id="wrapper">
   <h1>Simple Chat</h1>
   <div id="messages"></div>
   <div class="nic">
    Your Name
    <input id="name" name="name" type="text"/>
   </div>
   <textarea id="message"></textarea>
   <input id="send" type="submit" value="Send"/>
  </div>
 </body>
 </html>

The important bit here is the inclusion of /socket.io/socket.io.js. This is the client-side piece of socket.io and will provide us with a simple way to communicate with our server. The coolest part is that the socket.io Node module sets up this route for us on the server, so we don’t have to do anything server-side to get this route to work.

To organize our chat code, we are going to create a JavaScript module which will provide a single, global instance to utilize. To start, let’s just get the module code:

//Create a chat module to use.
 (function () {
 window.Chat = {
 };
 }());

This will create a single instance of the Chat object in the global scope. However, we are going to need our Chat object to do something. Initialization is always pretty important, so we can add that next.

//Create a chat module to use.
 (function () {
 window.Chat = {
  socket : null,
 
  initialize : function(socketURL) {
   this.socket = io.connect(socketURL);
 
   //Send message on button click or enter
   $('#send').click(function() {
    Chat.send();
   });
 
   $('#message').keyup(function(evt) {
    if ((evt.keyCode || evt.which) == 13) {
     Chat.send();
     return false;
    }
   });
 
   //Process any incoming messages
   this.socket.on('new', this.add);
  }
 };
 }());

In the initialize method, we are setting up the socket.io connection, subscribing to the new event, and making sure the send button and enter key do something productive. There is just one problem here, we don’t have an add function for the socket.on call to use. Let’s add that.

//Create a chat module to use.
 (function () {
 window.Chat = {
  socket : null,
 
  initialize : function(socketURL) {
   this.socket = io.connect(socketURL);
 
   //Send message on button click or enter
   $('#send').click(function() {
    Chat.send();
   });
 
   $('#message').keyup(function(evt) {
    if ((evt.keyCode || evt.which) == 13) {
     Chat.send();
     return false;
    }
   });
 
   //Process any incoming messages
   this.socket.on('new', this.add);
  },
 
  //Adds a new message to the chat.
  add : function(data) {
   var name = data.name || 'anonymous';
   var msg = $('<div class="msg"></div>')
    .append('<span class="name">' + name + '</span>: ')
    .append('<span class="text">' + data.msg + '</span>');
 
   $('#messages')
    .append(msg)
    .animate({scrollTop: $('#messages').prop('scrollHeight')}, 0);
  }
 };
 }());

Take some message data and add it to the DOM, that’s all we are doing here. Nothing special.

The final piece to this puzzle is sending the data.

//Create a chat module to use.
 (function () {
 window.Chat = {
  socket : null,
 
  initialize : function(socketURL) {
   this.socket = io.connect(socketURL);
 
   //Send message on button click or enter
   $('#send').click(function() {
    Chat.send();
   });
 
   $('#message').keyup(function(evt) {
    if ((evt.keyCode || evt.which) == 13) {
     Chat.send();
     return false;
    }
   });
 
   //Process any incoming messages
   this.socket.on('new', this.add);
  },
 
  //Adds a new message to the chat.
  add : function(data) {
   var name = data.name || 'anonymous';
   var msg = $('<div class="msg"></div>')
    .append('<span class="name">' + name + '</span>: ')
    .append('<span class="text">' + data.msg + '</span>');
 
   $('#messages')
    .append(msg)
    .animate({scrollTop: $('#messages').prop('scrollHeight')}, 0);
  },
 
  //Sends a message to the server,
  //then clears it from the textarea
  send : function() {
   this.socket.emit('msg', {
    name: $('#name').val(),
    msg: $('#message').val()
   });
 
   $('#message').val('');
  }
 };
 }());

With socket.io, you do two things: listen to events and trigger events. You listen with on (as we have seen), and you trigger events with the emit method. So when a message is ready to be sent, all we have to do is “emit” it with the message data. It will then be picked up on the server and emit it back out to all the sockets connected.

The only thing left to do is include it in the HTML and initialize it.

<!DOCTYPE HTML>
 <html>
 <head>
  <title>Simple Chat</title>
  <script type="text/javascript" src="/socket.io/socket.io.js"></script>
  <script 
    type="text/javascript"
    src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js">
  </script>
  <script type="text/javascript" src="chat.js"></script>
 </head>
 <body>
  <div id="wrapper">
   <h1>Simple Chat</h1>
   <div id="messages"></div>
   <div class="nic">
    Your Name
    <input id="name" name="name" type="text"/>
   </div>
   <textarea id="message"></textarea>
   <input id="send" type="submit" value="Send"/>
  </div>
  <script type="text/javascript">
   $(document).ready(function() {
    Chat.initialize('http://localhost/');
   });
  </script>
 </body>
 </html>

There it is, a complete chat application. If you run the Node script, it will start up and let you know socket.io is ready. Then you can bring up localhost and start chatting with…well, yourself if you run it locally.

Hopefully, this has been an informative, quick introduction to using WebSockets in Node.js.