An Introduction to Meteor JS

30 May 2015

Here is an introduction to meteor js and the principles meteor js embodies.

I gave a talk recently on Meteor JS at the WAPRO meetup in Long Beach, CA. This is a deeper dive into the examples that I talked about. Follow along the code examples by downloading the code with this link. Here is a link to the slides

The principles of Meteor

Here are the principles verbatim from the meteor docs.

  1. Data on the wire
  2. One language
  3. Database everywhere
  4. Latency Compensation
  5. Full stack reactivity
  6. Embrace the ecosystem
  7. Simplicity equals productivity

The examples

Data on the wire

Meteor sends data, not presentation. Meteor delegates presentation to clients and sends data to be rendered by clients. This is now the approach many applications take think single page applications. Many applications accomplish this through REST APIs.

Meteor uses a distributed data protocol(DDP) over web sockets to send and receive data from clients. This architecture is much easier to use then REST. Meteor offers a publish/subscribe approach that takes care of the heavy lifting of handling responses/requests.

Chrome Devtools displaying data on the wire alt text

One language

Meteor applications support running the same code on the server and client. Typically, modern web applications have more than one programming language. JavaScript for the client and ruby/python/java/etc running on the server for example.

Meteor runs JavaScript everywhere because it is built on top of Node JS. Allowing for the idea of write once, run everywhere. An integration that meteor supports is Cordova Phonegap for deploying native applications.

One language supported on client and server

Meteor.methods({
  'sharedCode': function () {
    if (Meteor.isServer) {
      console.log("it's on the server");
    } else if (Meteor.isClient) {
      console.log("it's on the client");
    } else {
      console.log("where is this?");
    }
  }
});

if (Meteor.isClient) {
  Meteor.call('sharedCode');
}

if (Meteor.isServer) {
  Meteor.startup(function () {
    // code to run on server at startup
    Meteor.call('sharedCode');
  });
}

Database everywhere

With Meteor the database is accessed through the same API. Out of the box, Meteor supports Mongo DB. The client doesn’t have “direct” access to the database. Meteor achieves this through an in-browser implementation of the mongodb (called minimongo). Meteor keeps the client database in sync with the actual database through DDP.

// create/access a collection in mongodb/minimongo
MyCollection = new Mongo.Collection('a_mongo_collection');

if (Meteor.isClient) {
  Tracker.autorun(function () {
    // the `find` method is used to query documents from minimongo
    // and the mongodb. The minimongo supports most of the mongodb
    // selectors and modifiers.
    MyCollection.find({}).fetch().forEach(function (doc) {
      console.log("Found " + doc.text);
    });
  });
}

if (Meteor.isServer) {
  // same `find` method
  if (MyCollection.find({}).count()) {
    return;
  }

  _.range(5).forEach(function (i) {
    MyCollection.insert({
      text: "this is doc " + i
    });
  });
}

Latency Compensation

Web applications today need to be fast. Many applications will wait for a response from the server before proceeding.

Meteor assumes that the operation will run successfully and not wait for the server before proceeding. It will reconcile any errors or differences when the server does respond in order to be compliant with the final outcome of the operation.

Score = new Mongo.Collection('score');

if (Meteor.isClient) {

  Template.hello.helpers({
    counter: function () {
      var score = Score.findOne({}) || {};
      return score.num || 0;
    }
  });

  Template.hello.events({
    'click button': function (e) {
      // increment the counter when button is clicked
      $(e.target).hide();

      Meteor.call('inc', function () {
        $(e.target).show();
      });
    }
  });
}

Meteor.methods({
  'inc': function () {
    if (Meteor.isServer) {
      // simulate a slower operation on the server
      // then increment score by 2 on the server
      Meteor._sleepForMs(2000);
      Score.upsert({ only: 1 }, {
        $inc: {
          num: 2
        }
      });
    } else {
      // increment the score by 1 on the client
      Score.upsert({ only: 1 }, {
        $inc: {
          num: 1
        }
      });
    }
  }
});

Full stack reactivity

Today web applications tend to be “real time.” This means that as things happen users expect to see the changes as they happen. This means that as changes to data happen the client must represent these changes to the end users. Meteor solves this through the Tracker package on the client.

// demonstration for client only right now
if (Meteor.isServer) {
  return;
}

// client only collection
coordsCollection = new Mongo.Collection(null);

Template.reactivity.onRendered(function () {

  // bind an event handler on the mousemove event
  $(document).on('mousemove', function (event) {
    // query our one coordinate document
    var coord = coordsCollection.findOne();

    // update the document as the mouse cursor moves
    coordsCollection.upsert({ only: 1 }, {
      $set: {
        x: event.pageX,
        y: event.pageY
      }
    });
  });
});

Template.reactivity.helpers({
  coord: function () {
    // create a dependency on this document
    // and update the template as this document changes.
    return coordsCollection.findOne({
      only: 1
    });
  }
});
<template name="reactivity">
  <h3>Reactivity</h3>
  <!-- unpack our coordinates from the coordinate document -->
  <p><b>x:</b>{{coord.x}}, <b>y:</b>{{coord.y}}</p>
</template>

Embrace the ecosystem

Meteor is open source. Allowing for an open platform. As of now, Meteor is in the top ten starred repositories on GitHub. Meteor is a collection of packages similar to packages in node js or gems in ruby. There are already a number of packages open sourced by the community allowing for the integration of existing libraries.

Simplicity equals productivity

Baking simplicity into Meteor allowed for an easier adoption. Meteor is attractive to hobbyist and professional programmers. Allowing for rapid prototype and application development. For this talk I wanted to build a multiplayer game to demonstrate the various principles. It took me less than a week to have something playable by friends.

Meteor, a web platform built for the future of development

Meteor is still relatively new. Everyday, it gathers more support. Since 1.0, meteor has been gaining a lot of traction. I am excited to see where the platform as whole goes and see what people can build on it.