Single Page App Architecture

What Are Single page apps?


A single page app is an app that runs entirely on the client-side (ie. browser) with the server providing services such as data, processing, auth etc. 

The key difference to SPA's is that unlike the old model, the application does not refresh the page in order to navigate or instantiate new views. Generally speaking all core assets are loaded by index.html and further assets are lazy loaded when required.  

Why Would I want to build one?

The main reason to build an SPA is if your existing or planned backend is a pure data service. Basically if you're serving nothing but JSON or XML or some other form of raw data that needs to be digest and displayed, SPA really are a way to go. 
Another reason might be that you're planning to take the jump and build your backend with node and would like to share code. 
With that said, you should think hard about the decision to go SPA because once you're in the groove, changing to another arch generally means a rewrite, and then your boss will really start to appreciate your talents. 

MV-whatever


There are 3 major design patterns for organizing SPAs
  • MVC - Model View Controller
  • MVP - Model View Presenter
  • MVVM - Model View ViewModel

As you can see, the difference comes down to the glue layer between the model and view; And although the patterns vary on their implementation, the fundamentals are all the same. 
The key is that it's not that choice itself that matters but that it fits your apps' particular requirements.

Model-View-Controller


Model-view-viewmodel

Model-view-presenter


Folder structure

The key here is to keep it simple, the last thing you want is to muck about with relative paths and configuration with loaders like RequireJS.

Modules

Browserify vs RequireJS vs Custom

Modularizing your code is not a question, however, which system to use definitely is. The loaders mentioned above are one way to go, but sometimes, they're simply overkill. Sometimes all you really need is a few <script src=""> tags, and bootstrap file to kick off the party. 
As always your requirements should be dictating the right path to choose. 

The module pattern

The module pattern is good emulating privacy in Javascript but it's also a fundamental building block for the facade pattern we'll look at next. That IIFE let's you easily hide any implementation details and only export the desired interface.  
(function(app) {
  var hiddenObj = {};  hiddenObj.method1 = function() {};  hiddenObj.method2 = function() {};  hiddenObj.method3 = function() {};
  app.export = {    exported: hiddenObj.method1,    exported1: hiddenObj.method2  };})(simpleBB);

FACADES and mediators


Facade - Comp Sci word used to describe the interface that a module exposes to it's consumers.

Mediator - A word used to describe what is essentially a simple event bus object used for communication between the app core and modules and between modules themselves. This object often has a pub/sub facade. 


The mediator

var mediator = (function(){
    var subscribe = function(channel, fn){},
 
    publish = function(channel){};
 
    return {
        channels: {},
        publish: publish,
        subscribe: subscribe,
        installTo: function(obj){
            obj.subscribe = subscribe;
            obj.publish = publish;
        }
    };
 
}());

Resulting architecture


Hierarchical structures

When it comes to dealing with hierarchical structure (and you will) the framework should really be lifting you up here and providing facilities for making this easier. Even though I love backbone, one of it's major lacking features is any kind of guidance or support for hierarchy. Plugins like Backbone-Relational have emerged, but even now most of them are simply a pain to deal with. 
Interestingly, Angular is one of the only frameworks where dealing with it is really not so bad, which probably has something to do with those magic bindings and plain object models. Either way, be prepared to suffer and maybe even write your own solution.

Knowing your history

The first rule of the dealing with the back button is you don't break the back button.
The second rule of dealing with the back button is you don't break the back button. 
There is no third rule. 
Users have a significant expectation of the back button, and that expectation is 'bring me back to where I was before'. Your routing structure and view handling code needs to be designed in such a way that the back button either brings up the previous view or reconstructs previous state.  

The environment

Grunt, Yeoman, Bower, Mocha

Don't reinvent the wheel! The 4 tools mentioned above will help you scaffold out your app, build it for production, manage your dependencies and test your application.

In the rare scenario where one of those tools doesn't do what you need, Grunt, Yeoman and Mocha are massively flexible and support plugins to extend or improve their functionality.

The war on frameworks

MVC Frameworks: 

  • EmberJS
  • Angular
  • Batman

    MVP Frameworks: 
    • Riot.js
    • Backbone*

    MVVM Frameworks:
    • KnockoutJS
    • Knockback

    The war on frameworks

    MVC Frameworks: 

    • EmberJS
    • Angular
    • Batman


    MVP Frameworks: 
    • RiotJS
    • Backbone

    MVVM Frameworks:
    • Knockback
    • KnockoutJS

    Crawlability and SEO

    So you have a beautiful app, it's tested, well written, everything works, but then Google Bot comes around and everything goes down the drain. At the time of writing, most crawlers can't properly execute your js and crawl the resulting DOM. 

    Headless browser to the rescue! Spin up an instance of PhantomJS and have any connection from known crawlers redirect to it. Is this ideal? No. Is it a workaround/hack/dirty/costly/unseemly/resource hog/adjective? Yes. Will it get your boss off your case? Maybe.


    alternatives: ZombieJS, HtmlUnit

    The land of Mobile


    The general rule for ensuring app functionality on mobile is testing, testing, testing. There's simply no way around it. 
    A fairly good pattern to follow is to ensure your code is as standard ES5 as possible, and shimming anything that might be missing. 
    Mobile is hard enough as it is, and the best protection is a good test suite and a killer integrated testing solution like TravisCI and friends.

    Links and references

    SPA Architecture - Addy Osmani's excellent architecture article.

    MVC Architecture - MVC architecture for JS apps.  

    TodoMVC - Great site for comparing popular JS frameworks

    Headless Browsers - A list of headless browsers

    Yeoman, Grunt - Scaffolding and build tools

    Mocha - Testing framework


    Made with Slides.com