Nazanin De's Blog

Projects, Ideas and thoughts

Angular 2 Universal: Isomorphic Javascript in Angular 2

Defining the term isomorphic in Javascript means to be able to run the same line of code both on the browser and the server so the front-end and back-end having the same code.
Looking into the meaning of the isomorphic word more closely we will find "corresponding or similar in form and relations." Which means two entities which are not the same but look the same. In other words means running the same code on different environments.

Nowadays we run Javascript code not only on the browser and server but also on mobiles, micro-controllers like Piis and Arduinos and even embedded devices.

Recently people started calling isomorphic javascript, universal javascript.Ok. Where ever boat flows...

How to make our app isomorophic?

First is using NodeJS server with the Javascript code which enables reusing the same Javascript code both on the browser and the server. Second is using frameworks out there which enables isomorphical javascript coding. There are so many of them out there some cool ones are:

  • ReactJS
  • Meteor
  • Rendr: Render your Backbone.js apps on the client and the server, using Node.js.
  • Mojito: Build high-performance, device-independent HTML5 applications running on both client and server with Node.js.
  • LazoJS: A client-server web framework built on Node.js that allows front-end developers to easily create a fully SEO compliant, component MVC structured web application with an optimized first page load. and Finally....
  • Angular 2 Universal
Why isomorphic?
  • Better overall user experience
  • Search engine indexable
  • Easier code maintenance
  • Free progressive enhancements
Angular 2 Universal Overview

I would like to cover how to set up a very simple application with Angular 2 Universal here. If you have not got a chance to work with Angular 2 yet here is a starter kit to get you up and running: https://github.com/AngularClass/angular2-webpack-starter

In high-level view there are two main component in Angular Universal:

1- Generate all HTML for a page on a given route or rendering on the server

2- Transition from the server view to the browser view in the client browser

There are two approaches to follow pre-rendering and re-rendering.
pre-rendering means leveraging one of the Universal build tools (i.e. gulp, grunt, broccoli, webpack, etc.) in order to create static HTML for all your routes at build time and then deploy that static HTML to a CDN. This approach is highly scalable and performant.

re-rendering means dynamically re-render the application for each request on the server. For having better performance and scalability caching is definitely an option here.

According to Angular 2 Universal documentation here is the throughout flow:

1- Browser receives initial payload from server
2- User sees server view
3- Preboot creates hidden div that will be used for client bootstrap and starts recording events
4- Browser makes async requests for additional assets (i.e. images, JS, CSS, etc.)
5- Once external resources loaded, Angular client bootstrapping begins
6- Client view rendered to the hidden div created by Preboot
7- Bootstrap complete, so Angular client calls preboot.done()
8- Preboot events replayed in order to adjust the application state to reflect changes made by the user before Angular bootstrapped (i.e. typing in textbox, clicking button, etc.)
9- Preboot switches the hidden client view div for the visible server view div
10- Finally, Preboot performs some cleanup on the visible client view including setting focus

Now let's set go over setting up a very simple Angular 2 app with Angular 2 Universal. First we need a NodeJS server up, here is a simple server NodeJS server in Angular2:

import * as express from 'express';  
import {ng2engine} from 'angular2-universal-preview';

// Angular 2 App import
import {App} from './src/app';

let myApp = express();

// Express Views
myApp.engine('.ng2.html', ng2engine);  
myApp.set('views', __dirname);  
myApp.set('view engine', 'ng2.html');


// static files
myApp.use(express.static(__dirname));


myApp.use('/', (req, res) => {  
  res.render('index', { App });
});


myApp.listen(3000, () => {  
  console.log('Listen on http://localhost:3000');
});

Next we need to have our universal module file:

declare module "angular2-universal-preview" {  
  function ng2engineWithPreboot(): any;
  function ng2engine(): any;
  function bootstrap(component: any, providers?: any): any;
  var BASE_URL: any;
  var BASE_URL: any;
  var PRIME_CACHE: any;
  var HTTP_PROVIDERS: Array<any>;
}

Then we set up a very basic angular 2 module, Since Pokemon market is pretty hot now let's have a single page app which everyones enter their favorite Pokemon name:

import {Component} from 'angular2/angular2';

@Component({
  selector: 'myApp',
  template: `
  <div>
    <h3>My favorite Pokemon is: {{ pokName }}!</h3>
    Pokemon name: <input type="text" [value]="pokName" (input)="pokName = $event.target.value" autofocus>
  </div>
  `
})
export class myApp {  
  pokName: string = 'Ponyta';
}

Now we need to bootstrap our app with Angular Universal:

import {bootstrap} from 'angular2-universal-preview';

import {myApp} from './myApp';

bootstrap(myApp);  

And lastly the HTML file:

<!DOCTYPE HTML>  
<html lang="en">  
<head>  
  <meta charset="UTF-8">
  <title>Favorite Pokemon Picker</title>
</head>  
<body>

  <myApp>
    Loading Pokemons...
  </myApp>
  <-- Webpack bundle -->
  <script src="/__build__/bundle.js"></script>
</body>  
</html>  

This was a very basic presentation of Angular 2 Universal if you like to start learning more there is a pretty good starter-kit out there that I strongly recommend using it.