Meteor: Introduction and Example app

Image credits - Ed Sweeney (http://www.flickr.com/photos/edsweeney/)I’ve just discovered Meteor and I’m currently in the honeymoon phase of this relationship. I realize that it’s still early in development but it’s one of the first truly inspiring full-stack web development platforms I’ve seen in a long time. Built on node.js, it consists of a JavaScript server (in a node.js container) and JavaScript client. The dynamic interaction between the client and server allows for a very simple, seamless way to create surprisingly complex web applications. In short, any changes to the back-end data automatically update front-end templates that use that data.

One of the important side-effects of the client/server interaction is how effortless it is to build applications that utilize dynamic data across browsers. Since all of the publish/subscribe code is abstracted out, the code to do client/server interaction is simple and clean. Something like a dynamically updating chat window is a piece of cake. Imagine a mapping application where multiple clients can be watching dynamically changing positions of characters on a map.

Example

As an introduction, I put together a very simple example to show the basic Meteor application components. In the example, I’ve built a basic app where clients can connect and participate in a chat log.

The first step is to create the html file with templates. In this case it’s just a simple html file that renders an input portion and then a list of all chat entries.

chat.html:

<head>
    <title>Simple Chat</title>
</head>

<body>
<!-- Just render the two templates -->
{{> input}}
{{> entries}}
</body>

<!-- Template for showing the input controls -->
<template name="input">
    <p>User: <input type="text" id="user"></p>

    <p>Message: <input type="text" id="message"><input type="button" id="sendMessage" value="Send"/></p>
</template>

<!-- Template for displaying all entries returned -->
<template name="entries">
    {{#each entries}}
    <strong>{{name}}:</strong> {{message}}<br>
    {{/each}}
    <p><input type="button" id="clear" value="Clear All"/></p>
</template>

NOTE: By default Meteor uses handlebars templating but allows other template mechanisms.

The next step is to create the JavaScript for setting up the entries in the database and for handling the user adding inputs. Notice there are two sections that use the Meteor API properties, Meteor.isClient and Meteor.isServer, to determine how the code is organized. The most important part about this file is the creation of the Entries collection and exposing that collection to the “entries” template defined in the html file. In addition to this, there are two events created here for adding entries (from the “input” template defined above) and clearing all events (also in the “entries” template).

chat.js:

// create an entries collection in the MongoDB db
Entries = new Meteor.Collection('entries');

if (Meteor.isClient) {

    // expose the Entries collection to the entries template (as 'entries')
    Template.entries.entries = function () {
        // return all entries sorted by time
        return Entries.find({}, { sort: { time: -1 }});
    }

    // create events for the 'input' template
    Template.input.events = {
        // map the event (click) for the control for the given selector
        'click input#sendMessage': function (event) {
            var name = document.getElementById('user');
            var message = document.getElementById('message');
            if (message.value != '' && name.value != '') {
                // add the entry to the list of entries
                Entries.insert({
                    name: name.value,
                    message: message.value,
                    time: Date.now()
                });

                document.getElementById('message').value = '';
                message.value = '';
            }
        }
    }

    // create events for the 'entries' template
    Template.entries.events = {
        // map the event (click) for the control for the given selector
        'click input#clear': function (event) {
            // make call to a server-side function to do remove the entries,
            // since you can't just call anything you want from the client
            Meteor.call('removeAllEntries');
        }
    }

}

if (Meteor.isServer) {
    Meteor.startup(function () {
        // define some methods on the server
        return Meteor.methods({
            removeAllEntries: function () {
                return Entries.remove({});
            }
        });
    });
}

This code is so simple it barely needs any explanation (especially since I went a tad overboard with the explanatory comments). The only possibly confusing part is that we have a “click” handler for the “#clear” input button but it makes a Meteor.call to a server-side function to do the actual removing of the entries. The reason for this is that there are some Collection methods that, by default, do not allow calls from the client (Collection.remove using a non-ID selector being one of them). Obviously this means two things: there is some level of call security (and that can be overridden to allow/deny calls to these methods) and, more importantly it implies…

The handler that doesn’t use the server call is modifying the model from the client side! Yup, using normal JavaScript calls to the collection, the code to actually handle the database insertions doesn’t need to be done server-side.

To run the code, we simply open a terminal in the folder where the files are and run:
meteor.

This starts a server on the localhost at port 3000.

Automatic Client Updating

What you don’t see in the code is what happens to the browser when the user “sendMessage” button is clicked. Obviously the event handler we’ve defined gets called and the entry gets added to the collection, and subsequently to the database…all on the client side. While that’s very cool, notice we don’t ever make a call to update the “entries” template. It happens automatically. 

Not only does the client that sent the event request see the list of entries updated with the new entry, more importantly, any clients that are viewing the page with the “entries” template will also see the updates. This is without any special code or call handling.

Magic. 🙂

meteor-chat

File Organization

Although this example contains all of the scripts, both server and client, in a single file, it is possible to reorganize your code up into different files. Meteor provides a special folder naming mechanism for specifying files that are server-side only (server and private folders). Outside of those folders, all JavaScript files in your folder hierarchy are bundled and loaded to both the server and the client. The public folder is the traditional place for serving publicly available resources like images.

Unlike a traditional server-side application, Meteor preprocesses the html files. Templates sections are converted to JavaScript to handle the client-server interaction. As you can see above, that interaction is quite seamless and the functional gears are hidden from the developer (unless you want to find them of course).

Conclusions

Some of the design approaches used with the Meteor platform have massive potential. The use of reactive programming and platform packages is, in my opinion, a big step forward. The architecture cleanly abstracts the sometimes messy framework code and encourages simple code.

My primary reservations right now consist of two facts:

1) it is a relatively immature platform. As a specific example, MongoDB is currently the only well-supported database. Others could be on the way but at the moment it has the most support. Regardless of how well designed it may be, there are always numerous questions you must ask when looking at a newly released platform. How scalable are Meteor applications? Will package developers continue targeting the non-standard Meteor package manager? As the Meteor platform is updated, will I need to completely refactor my existing code at every release?

2) Meteor is a full stack solution. It doesn’t really make sense unless you are starting a project from scratch and are willing to use it on both the server and client. The use of add-on packages helps alleviate some of the apprehension of selecting Meteor but there is no doubt that selecting it limits some of your options.

Final Word (so far)

Having built a few small applications with Meteor, my impressions are very good. I have been delighted with how much flexibility the design allows for your code. It is probably the first web-application platform I’ve worked with that makes server and client development appear simple and seamless.

I plan on using it for most of my personal projects to get more familiar with it (and inevitably move past the honeymoon). My initial opinion though leads me to hope that demand for Meteor development will grow in the new few months.

Brian Poteat

Brian Poteat

Brian Poteat

Latest posts by Brian Poteat (see all)

Tags:

Creative Commons License

This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.