Nodejitsu

Save time managing and deploying your node.js app

Single Page Apps with Node.js

About the author

Name
Location
Worldwide
nodejitsu nodejitsu

Other popular posts

- Scaling Isomorphic Javascript Code - Keep a node.js server up with Forever - Package.json dependencies done right
- npm cheat sheet - 6 Must Have Node.js Modules
Sign up to our platform for free - get $20 usage

While I was at nodeconf, I caught some of Henrik Joreteg's b-track talk which was an introduction to Single Page Apps. Node.js is a great platform for Single Page Apps because of it's real-time capabilities. This is a subject that has been obscured and confused by buzzwords and FUD. Henrik had a limited time to talk, so let's revisit this subject.


The Single Page App is not hype, it's an option.

First off, we need to clarify some nomenclature. Two characteristics clearly differentiate Web Sites from Web Apps. A Web Site is primarily informational, it has limited interactive behavior per page. A good example of a Web Site is eBay. Conversely, a Web App is far more interactive. It attempts to emulate or capitalize on familiar behaviors found in the applications on your desktop. An example of this might be the New York Times Web Reader App

A Single Page App is just a Web App, but what's unique is the anatomy. It's all in the name. Essentially, all of the markup is served up on the first request. Subsequent requests are then made to a REST API which provides JSON. Content transformations may also occur by means of a Web Socket or a remote procedure call.


The Advantages.

Aside from the obvious gains in user experience such as not having to reload the entire page for content changes, there's a long term Return of Investment to this approach. Since your data layer is decoupled from your UI, you can easily create a native app for a mobile device and leverage your existing APIs without the sky falling on you. Black boxes are cool. It's a lot simpler to write a next-generation app against an API of data than an router full of templates.

The bottom line is that single page apps are efficient. They have a small footprint on the server, consume less bandwidth and are more conducive to a service oriented architecture.


The Disadvantages.

What about SEO and the hash-bang shit storm I've been hearing about? This is FUD. There are certainly some radical perspectives on this subject, and usually extremists are narrow sighted. If you rely on SEO and you need your app to load without Javascript, you might not want to build a Web App. You should be building a Web Site. Advertising and promotion shouldn't drive the usability of an application.

Here's some art to try to explain the anatomy of a Single Page App.

Single Page Apps are simple. First, serve what's needed of the html. Second, speak with APIs using Javascript. Keep in mind there may be slightly more html than usual, so it should be very well organized and commented.


The Tools

SugarSkull

Single Page App is a misleading inscription. We actually have a single body of markup and we want to present the user with many views. Enter SugarSkull. SugarSkull is a client side URL router. It's the smallest amount of glue needed for building dynamic single page applications. Not a jQuery plugin: no dependencies.

// define a set of artificial urls
var router = Router({

  '/dog': { // a regular expression that represents a part of a route
    '/angry': { // another potential route part
      on: [growl, freakout] // a list of functions to execute when that route is requested
    }
    on: bark // a single function to execute whent the route is requested
  },

  '/cat': {
    '/squish': {
      once: freakout // a function that will only get executed once after the route is requested
    }
    on: meow
  }

});

You might also find that backbone.js is quite complimentary to SugarSkull with its Views and Models. Long lived data on the client means less round trips to the server, and that's one of the main goals.

Local Storage

Persistent local storage reduces round trips. The state of the application can be complex, user preferences and other unshared data can be decentralized. There are some good hacks for dealing with shitty browsers, Google Gears for example. But since you are creating a Web App you should be mostly concerned with modern browsers. You can find out more about it here as you dive into HTML5

Socket.io

"Socket.io aims to make realtime apps possible in every browser and mobile device, blurring the differences between the different transport mechanisms." What else can be said? This is exactly what we want for single page apps, responsive network interactions. Let's take a closer look.

On the client side

// Let's create a new socket and assign it to a local variable.
var socket = new io.Socket();

// Establish a connection back to the server from the browser.
socket.connect();

// Attach a handler to the window load event.
window.onload = function() {

  // Attach an event to the click event of document's body.
  document.body.onclick = function () {

    // Come up with some kind of stupid message.
    var message = 'The time is now ' + new Date();
    console.log('Sending the message "' + message + '"');

    // Send the message to the server.
    socket.send(message);
  };
};

// Create a handler for when a message arrives from the server.
socket.on('message', function(message) {  
  // When a message arrives, replace the body of the document with the message.
  document.body.innerHTML = message;
});

On the server side

// lets include some modules
var http = require('http'),  
    io = require('socket.io'),
    fs = require('fs');

// for the sake of this example, lets have some html to serve up.
var html = fs.readFileSync('socketio.html').toString();

// business as usual, create an http server.
var server = http.createServer(function (request, response) {  
  // serve up the client page.
  response.writeHead(200, {'Content-Type': 'text/html'});
  response.end(html);
});

// listen on port
server.listen(80);

// attach socket.io to the server
var socket = io.listen(server);

// set up an event that handles connections that get made to the server.
// the callback for this event will supply the socket as a parameter.
socket.on('connection', function(client) {  
  // on the socket we can attach events, lets respond to the client when
  // we recieve a message.
  client.on('message', function(message) {
    // we can log the message on the server side.
    console.log(message); 
    // then send it back to the client.
    client.send('Thanks for telling me "' + message + '"');
  });
});

Our communication vector is short, concise and that means snappy user interfaces. Socket.io is awesome. So is dnode. But Web sockets aren't available everywhere. Much of the web has started to uses REST. Porter is a nice little way to organize your REST communications.

Porter

Porter is a lightweight, resourced oriented, abstraction layer for JSON-REST. It will generate methods needed to access resources based on a JSON configuration. It will balance your code's signal to noise ratio by simplifying the communication interfaces. Applications with a lot of ajax calls can get ugly.

var porter = Porter({

  // define a resource group
  users: {
    // define a resource, a verb and a uri with some tokens replace
    search: ['get', '/api/users/:partialname'],
    update: ['post', '/api/apps/:username']
  },

  apps: {
    list: ['get', '/api/apps/:username'],
    create: ['post', '/api/apps/:username/:appname']
  }

});

// porter will transformt the above defintion into usable methods...
porter.users.search(

  { partialname: 'bill' }, // supply the value of the token to replace in the url

  function(error, response) {
    // do something...
  }

);

Conclusion

The idea is simple. Serve up a base presentation document. Manipulate it with Javascript. Get more data from the server and repeat previous step. From a performance perspective, Single Page Apps are nearly on parity with native apps (in the context of a modern browser). Nearly every operating system supports a modern browser. And with HTML, CSS and Javascript as the SDK way more people can join the party.