Nodejs is a new development platform that focusses on developing realtime applications. In this tutorial, we'll be learning how to create a full-fledged chatting application, complete with support for multiple users and multiple chat rooms. We will start slow at first and slowly build up to our goal. This is the first of a multipart turotial series.
Before we start, let us first clarify what node.js is, exactly. Is it a language? No. In fact, node.js is a runtime environment that can run JavaScript code. Also, it is build on top of Google's V8 JavaScript engine. Simply put, this means that Node.js is fast. Fast enough that you can write a web server in it and be confident that it'll handle loads just as well as a server written in C.
Node.js is good for writing application that require constant, or almost constant communication with the server. The thing that separated node from traditional web servers is that node.js server is not stateless - that basically means that the server remembers you between requests (In fact, this is not a feature of node but the websocket protocol but for this tutorial, it isn't necessary to know this). This is completely different from the traditional request-response paradigm that we've been using in the past two decades and it allows us to make applications that have real-time, two way interaction. Our chat application falls in this category.
One last thing: The application that we write in node.js is actually a server. Just like apache is a server. Node.js just provides a layer that can interface with low-level OS elements via JavaScript and so, we can actually write a server in a high-level language like JS. Fantastic, isn't it?
Okay, let's get started. We'll begin with a simple two people chat and slowly add to that to reach our final goal. Make sure that Node.js is installed.
- Socket.io : The library that allows the server and client to interact over a websocket.
- ExpressJS : A Node.js framework to minimize boilerplate code.
- Jade : The templating engine for Node.
You can either install each of these individually or use a package.json file that installs the packages for just this application and doesn't clutter your global development environment. Make a directory called and name it chat
. Move into the directory and create a package.json
file. In the file, enter this:
{
"name": "My Chat Application",
"version": "0.0.1",
"description": "A simple chat application.",
"dependencies": {
"socket.io": "latest",
"express": "latest",
"jade": "latest"
}
}
Now, open the terminal, navigate to the chat
directory and run:
$ npm install
This will automatically fetch and install the requirements and install them to the node_modules
directory.
One more thing before we begin: This app works over the websocket protocol which was introduced with HTML5 and is currently supported by a large number of browsers. However, not all browsers support it - older IEs (until IE 9) lack the support for it. Here's where socket.io comes in - it extends this support upto IE 5.5. So, you can be safe in the knowledge that your app will run on almost all browsers.
Now, we'll begin building the app itself. For this, we'll start by first making a simple webserver in node. Open a file called app.js and type in the following code in it:
var app = require('express')();
var server = require('http').createServer(app);
app.get('/', function(request, response){
response.send('<h1>It works!</h1>');
});
server.listen(3000, function(){
console.log('Listening on *:3000');
});
Tada! Now, we have a simple server that servers a response of 'It works!' to every web request. Go to your browser and point it to http://localhost:3000
and you should see the proper response. The code itself is self-explanatory.
Now, we'll see how to use the Jade templating engine for serving static pages via our server. Let's get right to it:
/* Port and server address. 0.0.0.0 ensures accessibility
outside to other computers on the network */
var PORT = 3000;
var SERVER_ADDRESS = '0.0.0.0'
var app = require('express')();
app.set('port', PORT);
// Setting up the directory in which we have out HTML templates
app.set('views', path.join(__dirname, 'views'));
// Specify the templating engine
app.set('view engine', 'jade');
// Some boilerplate for development
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
// Specify the public folder - for CSS, Images and JS
app.use(express.static(path.join(__dirname, 'public')));
// Create the server
var server = http.createServer(app);
// Use socket.io to get a handle to the server
var io = require('socket.io').listen(server);
// Start the server
server.listen(app.get('port'), SERVER_ADDRESS);
// Make a route and serve index.html on it
app.get('/', function (req, res) {
res.render('index', {
title: 'My Chat Application'
});
});
Now, go ahead and create two directories in your app directory - public
and views
. The public directory will contain your static public content - the CSS, JS, fonts, images, etc. The views directory will contain Jade templates.
Let us now make a simple index.jade file. Here's the Jade based code:
!!! 5
html
head
title My Chat Application
link(rel="stylesheet", href="/styles/style.css")
script(src="/socket.io/socket.io.js")
script(src="http://code.jquery.com/jquery-1.11.1.js")
script(src="/scripts/chat.js")
body
ul#messages
form(action='')
input#m(autocomplete='off')
button Send
Here's the CSS (styles.css)
:
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font: 13px Helvetica, Arial; }
form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages li { padding: 5px 10px; }
#messages li:nth-child(odd) { background: #eee; }
For now, leave chat.js
empty. We'll put in the necessary code as we go.
We now need to add the required CSS and JS files. Create two files:
styles.css
: Styling for the application underpublic/styles
.chat.js
: Client side logic for the application underpublic/scripts
.
Alright. Now, we're ready to implement server-side logic. But first, check whether this page works. As usual, run:
$ node app.js
Then, point your browser to http://localhost:3000
to see the rendered page. For now, it should be empty but you should be able to see the HTML by viewing the source of the page.
The server, for this first part of the tutorial is quite simple to write. Let us start with creating a basic connection to the server via socket.io
. Pu the following code somewhere below the server.listen
line in the app.js
file:
io.on('connection', function(socket){
console.log('a user connected');
});
Also, in the chat.js
file, add this code:
var socket = io();
Now, with the node server running, point your browser to http://localhost:3000
in a few tabs. You'll see something like this in the console output:
$ node app.js
listening on *:3000
a user connected
a user connected
a user connected
Here, each a user connected
line corresponds to a newly opened tab. The code is fairly simple: whenever a browser makes a request to the server it opens up a new socket to connect to the server. Once the connection is established, the connection
event occurs on the server. Here, we listen for this event on all incoming sockets and print an output to the console whenever we a connection occurs.
Now, let us modify this code so that it would:
- Gracefully handle of closing of sockets, and,
- Receive messages from the client.
Make the following changes to chat.js
:
io.on('connection', function(socket){
console.log('a user connected');
// prints sent messages to the console
socket.on('sendchat', function(msg){
console.log('message: ' + msg);
});
socket.on('disconnect', function(){
console.log('user disconnected');
});
});
What's happening here? Well, once a socket (a connection) is opened on the server, we can listen for events on this socket. Here, we listen for the sendchat
event to determine when the client sends a chat message.
But how does the client emit the sendchat
event, you ask? Well, just as we can listen for events, similarly, we can emit signals using socket.io
, on both the client and the server. Modify(chat.js)
like this:
var socket = io();
$('form').submit(function(){
socket.emit('sendchat', $('#m').val());
$('#m').val('');
return false;
});
Here, we're still opening a new socket on the client as the first thing. Then, we bind message form with the submit event. Whenever the the message form is submitted (that is, when a user sends over a chat message to the server), the sendchat
signal is emitted from the browser on the open socket. Indeed, this is the message that is detected on the server. Along with the emitted signal, we also need to send the actual message. This we do by picking up the message from the input box and pass this string as the second parameter to the emit function on the socket.
Now, we have a basic mechanism set that can deliver messages from the browser to the server. Now, all we need to do is to let the server broadcast the chat messages. To do this, socket.io
provides two different methods:
- Using
io.emit
, or, - Using
socket.broadcast.emit
.
In the first case, the signal is sent to all clients currently connected to the server, including yourself. The second method send the signal to everyone else (that is, everyone except you). For this tutorial, we'll use the first method.
Now, modify app.js
once more like this:
io.on('connection', function(socket){
console.log('a user connected');
// broadcasts sent messages to the all clients
socket.on('sendchat', function(msg){
io.emit('new message', msg);
});
socket.on('disconnect', function(){
console.log('user disconnected');
});
});
On the client side, we'll need to handle this event. For this, modify chat.js
like this:
var socket = io();
$('form').submit(function(){
socket.emit('sendchat', $('#m').val());
$('#m').val('');
return false;
});
socket.on('new message', function(msg){
$('#messages').append($('<li>').text(msg));
});
This listens on the socket for the new message
event and when it occurs, the JS code appends to the new message to a div.
With that we're done.