Single Page Application Ecosystem

Single Page Application aka SPA are the norms of the day for building HTML5 Web or Mobile Applications. They have been around for a while and lot of development is happening in various aspects of SPA. In order to begin understanding the SPA Ecosystem, we need to first understand how SPA can be broken down into various categories. The following diagram depicts that

SPA Ecosystem Categories

[singlepic id=53 w=800 h=600 float=]

The next step is to go through each block of the above diagram, explain each aspect and what Libraries exist today to support them. We will list either most popular libraries only

Build Tool, Dependency Management & Scaffolding

Every Software stack needs set of Build Tools. And as the Software Stack matures, Dependency and Scaffolding tools are added.

Yeoman

Yeoman is a combination of all the above and it has capability to Automate Tasks, pull dependencies and Scaffolds to generate code

Home Page - http://yeoman.io/

three tools for improving your productivity and satisfaction when building a web app: yo (the scaffolding tool), grunt (the build tool) and bower (for package management).

  • Yo scaffolds out a new application, writing your Grunt configuration and pulling in relevant Grunt tasks that you might need for your build.
  • Grunt is used to build, preview and test your project, thanks to help from tasks curated by the Yeoman team and grunt-contrib.
  • Bower is used for dependency management, so that you no longer have to manually download and manage your scripts.

Usage of Yeoman

npm install -g yo grunt-cli bower

Usage of Yo

Install Angular Scaffolding

npm install -g generator-angular

Running Angular Scaffolding

yo angular  

GruntJS Concept

GruntJS in most layman terms is Ant for JavaScript

GruntFile.js - Think of it like build.xml

// Project configuration.
grunt.initConfig({
  uglify: {
    my_target: {
      files: {
        'dest/output.min.js': ['src/input1.js', 'src/input2.js']
      }
    }
  }
});

Running uglify - Think about running ant task

grunt uglify

Bower Concept

Bower is a dependency management tool for JavaScript. It is similar to npm (package.json) of node. Just that Bower is for client side JavaScript

Install bower

npm install -g bower

Define Dependencies

{
  "name": "Bower Starter",
  "version": "1.0.0",
  "dependencies": {
    "requirejs": "latest",
    "jquery": "latest",
    "backbone-amd": "latest",
    "underscore-amd": "latest"
  }
}

Run bower to download dependency

bower install

Mobile Native Packaging

Mobile Native Packaging enables 2 things

  1. Allows HTML5 Apps to be packaged as Native Mobile Applications to be pushed on the app stores
  2. Enriches the HTML5 Apps by providing them native mobile features to use e.g Camera, GPS,  Contacts, Accelerometer etc

The few contenters in the top players for HTML5 Apps for Mobile Packaging are

PhoneGap

PhoneGap aka Cordova is one of the first HTML5 Cross Platform Mobile development framework. PhoneGap supports iOS, Android, Windows Mobile, Black Berry, Bada mobile platforms

PhoneGap can be extended by adding plugins to it.

In terms of Mobile Platform support and Plugin Support PhoneGap is leading

 

Trigger IO

Trigger IO is the newer kid on block when it comes to HTML5 Cross Platform Mobile Framework.

Trigger IO currently only supports Android and iOS, and has lesser support for its Plugins (in terms of number of plugins available). However, Trigger.io claims its JavaScript to native bridge is upto 5 times faster than PhoneGap. Also its builds are faster and easier for developers to manage.

Trigger.io also supports building iOS Apps on Windows platform, since it builds on the cloud.

 

 

StyleSheet Languages

CSS is an key aspect of SPA Space. Even with advancement with CSS3, coding in CSS has been a pain. With no features like inheritances, variables, mix ins creating themes or Responsive UI in basic CSS is a big pain.

That is where new age StyleSheet Languages come into Picture. These Languages provides things like

  1. Nested CSS Declaration - Hierarchical declaration of CSS classes
  2. Variables - Which are great of creating themes
  3. Mix ins - Reusable Snippets of CSS
  4. and more

There are tools available which can convert the Stylesheet written in these languages to CSS understood by the browser

Top Contenders in this space are

SaSS

Sass allows developers to write CSS in different and more power syntax (SCSS/SASS) and provides tools to convert CSS

sample.scss

$blue: #3bbfce;
$margin: 16px;

.content-navigation {
  border-color: $blue;
  color:
    darken($blue, 9%);
}

.border {
  padding: $margin / 2;
  margin: $margin / 2;
  border-color: $blue;
}

converts to following css after sass compilation

/* CSS */

.content-navigation {
  border-color: #3bbfce;
  color: #2b9eab;
}

.border {
  padding: 8px;
  margin: 8px;
  border-color: #3bbfce;
}

Less

On the same lines as SASS, Less is another library to write CSS in a more powerful syntax and compile it to CSS

Less Syntax

.transition(@transition) {
  -webkit-transition: @transition;
     -moz-transition: @transition;
       -o-transition: @transition;
          transition: @transition;
}
.opacity(@opacity) {
  opacity: @opacity / 100;
  filter: ~"alpha(opacity=@{opacity})";
}

a {
  .transition(all 0.4s);
  &:hover {
    .opacity(70);
  }
}

// Selector interpolation only works in 1.3.1+. Try it!
@theGoodThings: ~".food, .beer, .sleep, .javascript";

@{theGoodThings} {
  font-weight: bold;
}

Generated CSS

a {
  -webkit-transition: all 0.4s;
  -moz-transition: all 0.4s;
  -o-transition: all 0.4s;
  transition: all 0.4s;
}
a:hover {
  opacity: 0.7;
  filter: alpha(opacity=70);
}
.food, .beer, .sleep, .javascript {
  font-weight: bold;
}

 

Production Optimization

Product Optimization refers to anything which helps HTML based apps to run faster in the production environment. These refers to tools which can help us minify or obfuscate javascript, css and even HTML files. There are other tools which can concatenate images into large images and modify the css accordingly.

Popular tools here are

  1. jsmin
  2. uglify
  3. yui compressors
  4. etc many others

Typically most of these tools are now available as plugin to Grunt

Class System

JavaScript is a flexible language. Infact it is so flexible it allows you to write class in many manners. The main reason being there is nothing like a class in javascript, its a prototype based language. In this blog we will not go deep into javascript prototype (its a topic for another blog itself)

The most basic class definition can be as follows

var Employee = function(firstName, lastName){
   this.firstName = firstName;
   this.lastName = lastName;

   this.getFullName = function(){
       return this.firstName +" "+this.lastName;
   }
}

var employee = new Employee('Rohit','Ghatol');
console.log(employee.getFullName());

Another way of defining the same class could be

var Employee = function(firstName, lastName){
   this.firstName = firstName;
   this.lastName = lastName;
}
Employee.prototype.getFullName = function(){
   return this.firstName +" "+this.lastName;
}

var employee = new Employee('Rohit','Ghatol');
console.log(employee.getFullName());

The idea to behind talking about Class System is that you should be aware when you choose a profound JavaScript Library (profound meaning large enough), it is bound to have its own Class System

Backbone Class System Backbone would define its own class as follows

    Person = Backbone.Model.extend(
    { 
        defaults: { 
            name: 'Fetus', 
            age: 0, 
            child: '' 
        }, 
        initialize: function(){ 
            alert("Welcome to this world"); 
        } 
    }); 

    var person = new Person({ name: "Thomas", age: 67, child: 'Ryan'}); 
    var age = person.get("age"); // 67 
    var name = person.get("name"); // "Thomas" 
    var child = person.get("child"); // 'Ryan'

Sencha/ExtJs Class System Sencha Touch defines its classes differently

Ext.define('User', {
    extend: 'Ext.data.Model',
    config: {
        fields: [
            { name: 'id', type: 'int' },
            { name: 'name', type: 'string' }
        ]
    }
});

AMD - Asynchronous Module Definition

(Asynchronous Module Definitions)
  1. Allows creation of Modules
  2. Typically each Module has its own JS file
  3. One Module can load another, asynchronously
  4. Modules can be replaced by Mocks for Unit Testing
  5. Modules can be concatenated and Obfuscated
  6. Examples
    • RequireJS
    • CommonJS
    • ExtJS
    • etc

Lets go over AMD by looking at a  example, we will use require.js pseudo code for this

Understanding AMD by an Example

WITHOUT AMD

<head> <script src=“model.js”></script> <script src=“store.js”></script> <script src=“view.js”></script> <script src=“controller.js”></script> <script src=“app.js”></script> </head>

WITH AMD <head> <script src=“require.js” data-main=“app.js”></script> </head>

DEFINE MODEL JS

//Model.js
define(
    [],
    function(){
        return {
            "name":"Todo Model"
        };
    }
);

DEFINE STORE JS

//Store.js - with CRUD Operation
define(
    [‘Model’],
    function(model){
        return {
            “create”:function(){..},
            “retrieve”:function(){..},
            “update”:function(){..},
            “delete”:function(){..},
       };
    }
);

DEFINE VIEW JS

//View.js
define(
    [’jQuery’,’Model’,’Store'], 
    function($,model, store){
		store.update(model);

        //render 
		$(“.view”).html(…);

        return ..;
    }
) ;

DEFINE CONTROLLER JS

//Controller.js
define(
    [’jQuery’,’View’,’Store'],
    function($,view, store){
        view.setStore(store);
        $(“#placeholder”).html(view.el());
        return ..;
    }
) ;

DEFINE APP JS

//app.js
require(
    [‘jQuery’,’Controller’],
    function($,controller){
        $(“#loading”).html(“”); 	   	   
        controller.initialize();
    }
);

Writing JavaScript frameworks/libraries targeted for AMD

When Writing JS Libraries following care should be taken

  1. Your Library can be consumed by Any one
  2. That person may be using
    1. RequireJS
    2. CommonJS
    3. Directly including JS Library in HTML Page
  3. Your Library needs to be UMD
    1. It should load in all possible environments
      1. With RequireJS Module
      2. With CommonJS Module
      3. Without any Module (just by embedding javascript in page)

 Example of UMD

!function (name, definition) {
    if (typeof define == 'function' && define.amd) {
        //define module in Require JS
        define(definition);
    } else if (typeof module != 'undefined') {
        //define module in Common JS
        module.exports = definition();
    } else {
        //define module when JavaScript file is directly embedded in page
        this[name] = definition();
    }
}('MessageBus', function() {

    var MessageBus = function () {
        .......
    };

    MessageBus.prototype = {
        publish : function (channel,message){
            ......
        },
        subscribe : function (channels,callbacks){
            .....
        }
    };

    return MessageBus;
});

Router & History

Routers and History frameworks in JavaScript allow Single Page Applications to behave like any other Web Application and obey ground rules like following

  1. Obey Browser Back and Forward Buttons
  2. Allow Deep link/Book marking of state in SPA
  3. Programmatically allow manipulation of history

Example of How Routers & History Works Step 1 - User is at Ext.data.Store page in Sencha Documentation

Step 2 - User clicks the StoreManager link

Step 3 - This changes the Browser address to http://docs.sencha.com/touch/2-0/#!/api/Ext.data.StoreManager

Step 4 - The Router framework is listening to any change in URL and triggers creation of an addition Tab to show Ext.data.StoreManager's apis

Examples of Pure Router Frameworks are

  1. Sammy JS
  2. Pager
  3. Dave JS
  4. Cross Roads
  5. Path JS

Other profound frameworks like Sencha, EXTJS & Backbone have their own Routers built in

DOM Manipulation

DOM Manipulation is all about manipulating HTML DOM at runtime.

  1. Most Popular Framework - jQuery
  2. Other Frameworks
    1. ZeptoUI
    2. XUI

Apparently jQuery also provides other api apart from DOM Manipulation like Ajax API etc

MicroTemplates

A good design pattern when building UI in javascript is to keep the markup code out side the JavaScript View logic.

The idea is to have a clear separation of Concern

JavaScript View

  1. Access Model 
  2. Address UI Events

Markup Code aka Micro Template

  1. Map the Model attributes to the Markup
  2. Provide Markup with looping, conditional blocks capability

Example of Underscore Micro Template

<div id="placeholder"></div> <script type="text/javascript">

// Compile the template using underscore var tmplTxt = $("#search_template").html();

//_ stands for underscroe var template = _.template(tmplTxt, {label:"Hello World"} );

$("placeholder").html( template );

</script>

//Template put in the script tag

<script id="search_template" type="text/template"> <label><%=label%></label> <input type="text" id="search_input" /> <input type="button" id="search_button" value="Search" /> </script>

Once the MicroTemplate has run the div (placeholder) looks as follows

<div id="placeholder"> <label>Hello World</label> <input id="search_input" type="text" /> <input id="search_button" type="button" value="Search" /> </div>

Following examples of standalone Micro Template libraries

  1. underscore
  2. handlerbar
  3. moustache
  4. etc

MV * Frameworks

By MV * frameworks we mean any frameworks which approximates to any of the following design patterns

  1. Model View Controller
  2. Model View View-Model
  3. Model View Presenter (rarely seen in JavaScript but main framework for GWT)

MVC Design Pattern

 

 

Backbone is one of the popular MVC Framework, also one of the most flexible frameworks which can work with other frameworks. Backbone is really a MV* framework and not really a pure MVC framework. In Backbone the View and Controller boundaries are blurred and the View represents both. Apart from this, Backbone has Model, Collection and Routers.

Backbone MVC Code Snippets

Model

Person = Backbone.Model.extend({ 
    initialize: function(){ 
        alert("Welcome to this world"); 
    } 
}); 
var person = new Person({ name: "Thomas", age: 67});

View & Controller in View itself

SearchView = Backbone.View.extend({ 

    initialize: function(){       
        this.render();
    },
    render:function(){
        this.$el.html("<button id="button">Click Me</button>");
    }
    events: { 
        "click #button": "clickMe" 
    }, 
    clickMe: function( event ){ 
         alert("You clicked me"); 
    } 
}); 

// The initialize function is always called when instantiating a Backbone View. 
// Consider it the constructor of the class. 

var search_view = new SearchView($("#placeholder"));

In Backbone the View and Controller are combined into One. In the above code initialize() and render() method are View concept, and event object and clickMe() method are Controller concept.

Other Popular JavaScript MVC Frameworks are

  1. Angular Js
  2. ExtJS, Sencha Touch
  3. Ember JS
  4. Kendo UI
  5. etc

MV VM Design Pattern

 

 

MV VM framework is about View and View Model living in pair and View Model adapting the Model (Domain Model) for the View

HTML Markup aka View

<p>First name: <strong >todo</strong data-bind="text:firstName" ></p> <p>Last name: <strong>todo</strong data-bind="text:lastName" ></p>

JavaScript Code

function AppViewModel() {
    this.firstName = ko.observable("Rohit");
    this.lastName = ko.observable("Ghatol");
}

// Activates knockout.js
ko.applyBindings(new AppViewModel());

Output HTML Markup <p>First name: <strong >todo</strong data-bind="text:firstName" >Rohit</p> <p>Last name: <strong>todo</strong data-bind="text:lastName" >Ghatol</p>

 


MVP Design Pattern

 

 

 

Like I mentioned before MVP is Design Pattern worth knowing, but it is not popular in JavaScript world. However it is the official Design pattern for GWT (Google Web Toolkit)

.

.

.

Data bound Views

Data bound Views are views which take their data from a predefined data source. e.g GridView which talk to a Data Store which in turn reads out data from either a AJAX Source or Local Storage etc.

Following is how Sencha's Data Bound Views work

Following Libraries have Data Bound Views and Widgets (Views) in them

  1. ExtJs or Sencha Touch
  2. Backbone Js

 

Large Scale Application Frameworks

Design Patterns get us only so far when building Large Scale Applications. To really work on a Large Scale Application, we need an Architecture for it.

Aura Js is an upcoming popular Large Scale Application framework. It is based on the following design

[singlepic id=45 w=320 h=240 float=]

Aura Provides following

  1. A Framework to abstract out 
    1. DOM Manipulation Frameworks
    2. MV* Frameworks
    3. Any framework your application depends on
  2. Aura Core is an extensible Core, User Extensions can be added to it to expand its capability
  3. Out of the box Aura Core comes with
    1. DOM Manipulation APIs under the hood calling jQuery. This can be switch to Zepto or any other
    2. MVC APIs which under the hood call BackBone
  4. Anything like a Logging or Authentication or Ajax APIs which the product needs should be added to Aura as Extensions
  5. Widgets are Views (out of box uses BackBone) which are running in Aura Sandbox
  6. Extensions can be used to provide Widgets additional APIs vai the Sandbox
  7. Widgets communicate to other Widgets only through the Sandbox
  8. Widgets do not access DOM, Ajax or anything directly but uses Sandbox for everything

Code Snippet

Aura BootStrap Code

require(['aura/aura'], function (Aura) {
    var app = new Aura();

    app.use('extensions/storage');
    app.start({ widgets: 'body' });
});

Extension

define(['underscore'], function (_) {
    var app;
    var todos = [];

    function createNewTask(data) {
        var task = _.extend(data, {id: _.uniqueId('task')});
        todos.push(task);

        app.sandbox.emit('storage/newTaskCreated', task);
    }

    function toggleTask(data) {
        var task = _.find(todos, function(task) {
            return task.id === data.id;
        })
        var completed = task.completed || false;
        task.completed = !completed;

        app.sandbox.emit('storage/taskToggled', task);
    }

    function deleteTask(data) {
        todos = _.reject(todos, function (task) {
            return task.id === data.id;
        });

        app.sandbox.emit('storage/taskDeleted');
    }

    function editTask(data) {
        var task = _.find(todos, function(task) {
            return task.id === data.id;
        })
        task.description = data.description;

        app.sandbox.emit('storage/taskEdited');
    }

    return {
        initialize: function (application) {
            app = application;
            app.sandbox.on('ui/createNewTask', createNewTask);
            app.sandbox.on('ui/toggleTask', toggleTask);
            app.sandbox.on('ui/deleteTask', deleteTask);
            app.sandbox.on('ui/editTask', editTask);
        }
    };

});

Widet Code

define(['underscore'], function (_) {

    return {
        template: 
            '<header id="header">\
                <h1>todos</h1>\
                <input id="new-todo" placeholder="What needs to be done?" autofocus>\
            </header>',

        initialize: function () {
            _.bindAll(this);

            this.render();
            this.cacheElements();
            this.attachEvents();
        },

        render: function () {
            this.$el.html(this.template);
        },

        cacheElements: function () {
            this.$newTodo = this.$el.find('#new-todo');
        },

        attachEvents: function () {
            this.$el.find('#new-todo').on('keyup', this.createNewTask);
        },

        createNewTask: function(e) {
            if (e.which === 13) {
                var val = this.$newTodo.val();
                this.sandbox.emit('ui/createNewTask', {description: val});
                this.$newTodo.val('');
            }
        }
    };

});

Refer to Aura Todo MVC Example

Responsive UI

Response UI can mean number of things. However in the HTML5 world it means following

  1. SPA are responsive to any form factor and device
  2. Pages adapt to different Screen Sizes

This is best explained as an example

Look at the Screen shot below. This is how a responsive website looks on Desktop

[singlepic id=46 w=320 h=240 float=]

The same site adopts to the mobile browser as below. Notice the change in how menus are shown

[singlepic id=47 w=320 h=240 float=]

Further more see how Menus are loaded on mobile browser

[singlepic id=48 w=320 h=240 float=]

The two most popular Responsive UI framework out there are

  1. Twitter Bootstrap
  2. Zurb Foundation

Responsive UI frameworks are hard to define. They are really mix of

  1. Elaborate Grid System and CSS which make heavy use of Media Queries.
  2. Grid System is a way of saying that we will put the UI components across say 12 Columns in a Grid. Depending in the Screen size the Columns will stay intact or convert to Row as part of Responsive UI
  3. Media Queries are CSS snippets which apply themselves or remove themselves depending on Screen size. This how the above example worked. 
  4. CSS Styling for Tabs, Buttons, Section, Bread Crumbs etc
  5. JavaScript APIs for Tabs, Buttons, Sections etc
  6. Ready to use Conversional Look and Feel, so you don't need a Designer to launch your work

The best part of Responsive UI is that they can be applied independently of MV* Framework. Also Responsive UI are tools for doing Quick Mockups.

 

Widget Set

Widget Sets are referred to as Framework which provide Richer Widgets. There are pure widget set frameworks and other more profound javascript framework where widget set is one of the many part

One of the popular Pure Widget Set framework is jQuery UI.

[singlepic id=49 w=320 h=240 float=]

Other more popular and profound Frameworks with Richer Widget Sets are

  1. Sencha Touch/ExtJs
  2. Kendo UI
  3. etc

[singlepic id=51 w=320 h=240 float=]

[singlepic id=50 w=320 h=240 float=]

HTML5 Features

HTML5 Features are provided by the browser. However there are issues with cross browser compatibility.  Some browsers are better than others in supporting HTML5 Features.

A SPA Product needs to work on all sorts of Browsers. It needs to leverage features where they are available out of the box, and it needs to either simulate features or do a graceful fallback when the features are not available out of the box.

HTML5 SPA Product development needs two things

  1. Design Time Information to make critical decisions. What features to incorporate and what to let go.
  2. Runtime Libraries to detect HTML 5 Features, Simulate or do graceful fallback

Design Time Tools

Design time tools are for making decisions on which HTML 5 Feature to go with depending on the browser support available.

One of my favorite tool for this is http://html5please.com. Only only does it tell whether a feature is safe to use on all modern available browser, but it also recommends polyfills if required. It also cautions about a feature if polyfills are missing or major browser (e.g IE 10) is not supporting the feature

[singlepic id=52 w=500 h=350 float=]

Apart from this one there are the following

  1. http://caniuse.com
  2. http://html5test.com

Run Time Tools

Runtime tools in HTML5 are of 2 types

  1. Feature Detection and Fallback Mechanims
  2. Polyfills

Feature Detection and Fallback Mechanism

Modernizr is a popular JavaScript library which can provide details like which HTML5 Features are supported by the browser running it.

Modernizr.load({
  test: Modernizr.geolocation,
  yep : 'geo.js',
  nope: 'geo-polyfill.js'
});

In the above code we are testing if geolocation feature is available on the browser, if so use the geo.js javascript file, and if not then fallback using geo-polyfill.js. PolyFills

Polyfills are mechanisms to provide to a missing HTML5 Feature. e.g In IE6, there is no support for Canvas, we can add this support by using the ExCanvas Polyfill, which uses flash internally to do rendering, but adheres to the same canvas apis.

There are many polyfills out there. However using Polyfills can degrade performance (as these are not provided by browsers, but are software simulated). Here are few examples

  1. SVG Web - http://code.google.com/p/svgweb/
  2. ExCanvas - http://code.google.com/p/explorercanvas/
  3. Storage Polyfill - http://www.calormen.com/polyfill/#storage
  4. HTML5 Shiv - http://github.com/afarkas/html5shiv
  5. HTML5 Media - http://github.com/etianen/html5media
  6. Event Source - https://github.com/remy/polyfills/blob/master/EventSource.js

Visit this github repository to find all popular polyfills.

 

3D/2D Graphics/Visualization

3D and 2D Visualization even though part of HTML5 feature set , require special attention.

WebGL forms the basis for 3D Visualization and Canvas/SVG form the basic for 2D Visualization/Charts and Graphs

WebGL

Programming in WebGL is tough and unproductive. Abstraction level frameworks are required to ease programming effort when working with WebGL.

Popular 3D Libraries are

  1. Three.js
  2. X3DOM
  3. Scene.js
  4. etc

Three.js Demo

X3DOM Demo

 

Charts/Graphs

Charts and Graphs can be created in HTML5 using any of the following technologies

  1. Canvas
  2. SVG
  3. VML
  4. Divs

Charts and Visualizations libraries can be categorized roughly into two

  1. Actual Charts/Graphs Libraries
    1. High Charts
    2. JS Charts
    3. Plot Kits
    4. Google Visualizations
  2. Advanced more Generic Visualization Libraries
    1. D3JS

The key difference is D3JS is more generic and more power visualization framework. It should be used when more complex visualizations are required which are not available out of the box.

Like the following Back to Back Bar Chart.

 

[iajsfiddle fiddle="DWJ35" height="500px" width="100%" show="result,js" skin="default"]