Introduction to Realtime Web with Meteor and Node.js

Recently, there was a flurry of tweets that appeared on my Twitter timeline talking about Derby.js. I’ve never used a framework that did so much for you– realtime synchronization of the client and server. Essentially, this enables one to write an application in which two users edit the same text field–live–without writing too much code yourself. Derby handles all of the synchronization of the models and views. Think Google Docs collaborative editing.

That’s great, but after further investigation, it seems like Derby.js isn’t quite as mature as I’d like– it’s not 1.0 yet. To be fair, neither is Node.js (the platform behind Derby) or Meteor, but there seems to be quite a bit missing from Derby. For example, as far as I can tell, there’s no easy way to handle sessions. This may be a result of a lack of documentation, but it appears that the developers behind Derby are working on authentication at this moment. If anyone has writeup on how to handle sessions in Derby, I’d live to hear about it.

The one framework I always see compared to Derby.js is called Meteor. Similar to Derby, it handles things such as updating views live across multiple clients, though Meteor does it somewhat differently. While Derby is designed to be easier to use with different types of database systems, Meteor works closely with MongoDB. In fact, the client API for accessing the database is almost exactly like what you’d expect on the server-side with something like Mongoose.

While there are some drawbacks and controversies surrounding the framework (see Fibers vs Callbacks), Meteor looks like a pretty interesting option when creating an app that requires realtime feedback. Personally, I’m more attracted to the traditional callback style of programming of Derby, but the lack of robust documentation and a large developer community behind it is a huge blow to Derby’s usefulness. This will change over time, but at a much slower rate than Meteor, which recently received $11M+ in funding. This financial backing ensures that Meteor will remain around and supported, and for developers who need a financially and developmentally stable framework, the funding will only make Meteor more appealing.

Today, I want to go over how to create a really simple Meteor app. Essentially, this is a writeup for Tom's Vimeo screencast. One major difference between my writeup and Tom's video tutorial is the way we handle events in Meteor. Rather than copying and pasting code from one of Meteor's examples, I take you step by step through a custom implementation of handling the enter key press to submit a message. Let's begin!

Creating a Meteor App

One big plus of both Derby and Meteor is their respective command line tools. Unlike Derby, which uses Node’s native NPM tool, Meteor comes with its own installer.

From the terminal (on Mac OS X and Linux), run the following command. Ensure you already have Node installed.

$ curl https://install.meteor.com | /bin/sh

Meteor will do its thing, and install the command line tools.

To create a project, navigate to a directory and run the following command. This will create a subfolder and populate it with Meteor and a basic template for a realtime app.

$ meteor create chat

Now, you can run the app from the terminal. Simple navigate to the proper directory and run meteor.

$ cd chat
$ meteor
Running on: http://localhost:3000/

To see the template app, open any modern web browser and navigate to http://localhost:3000/.

If you want, you can even deploy it to Meteor’s own servers using the built in meteor deploy command.

$ meteor deploy my-app-name.meteor.com

You can leave the app running, since all browsers connected to it will update live once you save your code.

Developing the Chat App

In the folder generated by the meteor create command, you can see several different files. Depending on whether you have the ability to view hidden files, you may also see a .meteor folder. This folder contains Meteor itself, along with the MongoDB database file.

In the root folder for your app, you should see chat.html, chat.css, and chat.js. These three files should be self explanatory. The HTML file contains the templates and views for the app, both styled by chat.css. The Javascript file contains the scripts run on both the client and the server. This is important– do not put anything, such as configuration data and passwords, in this script since anyone can see it by viewing the source of your application.

Open the chat.js file in your favorite text editor. Personally, I use Sublime Text 2 for its simplicity and multi-cursor features.

You can see the following code in the chat.js file.


if (Meteor.is_client) {
  Template.hello.greeting = function () {
    return "Welcome to chat.";
  };

Template.hello.events = {
'click input' : function () {
// template data, if any, is available in 'this'
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
};
}

if (Meteor.is_server) {
Meteor.startup(function () {
// code to run on server at startup
});
}

Notice the Meteor.is_client and Meteor.is_server portions of the code inside of the if statements. Code inside of these blocks will only be run if the executing computer is a client or server, respectively. This demonstrates the code sharing abilities of Meteor in action.

Delete all of the code inside of the if(Meteor.is_client) statement and the entire Meteor.is_server if statement so you are left with the following.


if (Meteor.is_client) {

}

Notice, once you save the script file, your browser will immediately refresh and load the new script.

Creating the View

Before we modify the script file, the view that will show the chat log needs to be created.

Open the chat.html file in your text editor and delete the code in the body tag, as well as the template with the name of “hello”. Your code should look like the following.

<head>
  <title>chat</title>
</head>

<body>

</body>

Inside of the body tag, add the following.

{{> entryfield}}

Meteor uses a template system very similar to Mustache. The curly braces (mustaches– get it?) denote an action for the template system to perform. By simply typing a word in between two sets of mustaches ({{hello}}), the template system will replace that code with the variable hello. More on that later.

See how there is a greater than symbol (>) before the word “entryfield”? That designates for Meteor to render a template.

To create the template named “entryfield”, add the following below the body tag.

<template name="entryfield">
    <input type="text" id="name" placeholder="Name" /> <input type="text" id="message" placeholder="Your Message" />
</template>

The template tag has a single attribute in this case– the name of the template. This is what we use when rendering the template. Notice how the name of the template is the same as the code we inserted into the body ({{> entryfield}}).

If you look at your web browser, you can now see that it has refreshed and the inputs are being displayed.

Next, add in another mustache tag into the body to render the list of messages.

{{> messages}}

Finally, we need to create the template named “messages”. Copy and paste the following below the “entryfield” template.

<template name="messages">
    <p>
        {{#each messages}}
            <strong>{{name}}</strong>- {{message}}
        {{/each}}
    </p>
</template>

Notice the each clause. In Meteor, you can loop over an array in a template using the following syntax.

{{#each [name of array]}}
{{/each}}

Inside of this each loop, the context changes. Now, when referencing variables, you are referencing properties of each array element.

For example, in our chat app, we are looping over “each” of the elements in the array named “messages”. This array will look like the following.

[
    {
        "name": "Andrew",
        "message": "Hello world!"
    },
    {
        "name": "Bob",
        "message": "Hey, Andrew!""
    }
]

Inside of the each loop, you can see {{message}} and {{name}} being referenced. These will be replaced with the properties of each of the elements of the messages array (Andrew and Bob for the name, and the respective Hello messages).

Back in your web browser, you should see no change. This is because the messages array has not been passed to the template yet, so Meteor is looping over and displaying nothing.

Your final chat.html file should look like the following.


<head>
  <title>chat</title>
</head>

<body>
{{> entryfield}}

{{> messages}}
</body>

<template name="entryfield">
<input type="text" id="name" placeholder="Name" /> <input type="text" id="message" placeholder="Your Message" />
</template>

<template name="messages">
<p>
{{#each messages}}
<strong>{{name}}</strong>- {{message}}<br/>
{{/each}}
</p>
</template>

The Javascript

For now, most of what we will deal with is client-side code, so all code provided below goes within the Meteor.is_client if code block unless stated otherwise.

Before we actually write the code that displays the messages, we have to create a “Collection”. Essentially, this is a group of Models. In other words, in context of the chat app, the Messages collection will hold the entire chat log, and each individual message is a Model.

Before the if statement, add the following code to initialize the Collection.

Messages = new Meteor.Collection('messages');

This goes outside of the client-only code block because we want this Collection to be created for both the client and server.

Displaying the chat log is very easy since Meteor does most of the work for us. Simply add the following code inside of the if statement.

Template.messages.messages = function(){
    return Messages.find({}, { sort: { time: -1 }});
}

Let’s break it down–

Template.messages.messages = function(){ … }

The first section (Template) indicates that we are modifying the behavior of a template.

Template.messages.messages = function(){ … }

This second part indicates the name of the template. For example if we wanted to do something to the “entryfields” template, we would change the code to Template.entryfields.variable = function(){ … }. (Don’t do this now.)

Template.messages.messages = function(){ … }

Finally, the third section represents a variable in the template. Remember how we included an each loop that iterated over the messages variable? This is how we specify what messages really is.

If you go to your web browser, you will see that nothing has changed. This is still expected because while you are now fetching the messages, there are no messages to actually display.

Your chat.js file should look like this. It’s amazing that this is all of the code we need to display a real time log of chat messages on the server.

Messages = new Meteor.Collection('messages');

if (Meteor.is_client) {
Template.messages.messages = function(){
return Messages.find({}, { sort: { time: -1 }});
}
}

Adding a Message through the Console

This part is optional, though it can be helpful for debugging. If you just want to skip it and learn how to make the entry form react to key presses and such, continue below.

If you want to test your message display code, you can manually insert a record into the database. Open up your web console in your browser and type the following.

Messages.insert({ name: 'Andrew', message: 'Hello world!', time: 0 })

This creates a record in the database. If you did everything correctly, the message should also show up on the page.

The Message Entry Form

Back in the chat.js file, we are going to link the input form to the database to allow users to submit chat messages.

Add the following code at the bottom, but within, the if statement.

Template.entryfield.events = {
  "keydown #message": function(event){
    if(event.which == 13){
      // Submit the form
      var name = document.getElementById('name');
      var message = document.getElementById('message');
  if(name.value != '' &amp;&amp; message.value != ''){
    Messages.insert({
      name: name.value,
      message: message.value,
      time: Date.now()
    });

    name.value = '';
    message.value = '';
  }
}

}
}

This is a lot, so let’s go through it. As you might recall, the second property after the word Template defines which template we are modifying. Unlike before, where we were setting up code binding the database to the “messages” template, we are modifying the “entryfield” template.

The events property of the template contains an object with its keys in the following format.

"[eventname] [selector]"

For example, if we wanted to bind a function to the click event of a button with the ID of hello, we would add the following to the events object.

"click #hello": function(event){ … }

In our case, we are binding a function to the keydown event of the field with the ID of message. If you remember, this was set up earlier in the tutorial when we created our template in the chat.html file.

In the events object, each key has a function as its value. This function is executed with the event object passed as the first parameter when the event is called. In our chat app, every time any key is pressed (keydown) in the input field with the ID of “message”, the function is called.

The code within the function is fairly simple. First, we detect if the enter key was pressed (enter has a key code of 13). Second, we get the DOM elements of the two input fields by their IDs. Third, we check and ensure that the input values are not blank to prevent users from submitting a blank name or message.

It’s important to notice the following code. This is what inserts the message into the database.

Messages.insert({
  name: name.value,
  message: message.value,
  time: Date.now()
});

As you can see, this is similar to the code we inserted into the console, but instead of hard coding the values, we use the DOM elements' values. Additionally, we are adding the current time to ensure that the chat log is properly ordered by time.

Finally, we simply set the value of the two inputs to ‘’ to blank out the fields.

Now, if you go into your browser, you can try and input a name and message into the two input fields. After pressing enter, the input fields should be cleared and a new message should appear right under your input fields. Open up another browser window and navigate to the same URL (http://localhost:3000/). Try typing in another message, and

As you can see, Meteor is pretty powerful. Without writing a single line of code to explicitly update the message log, new messages appear and are synced across multiple browsers and clients.

Conclusion

While Meteor is pretty cool to work with and there are some pretty useful applications for it, like Derby.js, it is immature. For examples of this, just browse through the documentation and look for the red quotations. For example, the documentation states the following about MongoDB collections:

Currently the client is given full write access to the collection. They can execute arbitrary Mongo update commands. Once we build authentication, you will be able to limit the client’s direct access to insert, update, and remove. We are also considering validators and other ORM-like functionality.

Any user having full write access is a pretty big problem for any production app– if a user has write access to your entire database, this is a pretty big security issue.

It’s exciting to see where Meteor (and Derby.js!) is/are headed, but until it matures a little bit, it may not be the best choice for a production application. Hopefully the $11M in funding will go to good use.

To keep up with me, my articles and tutorials, you can follow me on Twitter.