Angular (2) Universal Server-Side Rendering Example

Since time immemorial, server side rendering was the standard method for printing on the screen. The point is that it turned HTML files in the server into acceptable information for a browser. In fact, at that time it was the only way. Though, as technologies have become more powerful and complicated, a lot of server-side logic was moved to the client side.

SPA + client-side rendering = the perfect match?

Currently, web applications are better known as single page applications (SPAs), what means that websites function as independent apps and communicate with servers via APIs. Modern sites have become more advanced and these days they offer improved user experience enabling users to exchange messages, shop, update on-line information, and so on.

Talking about client-side rendering (CSR), we should mention such benefits as improved maintainability, easier modularizing, plain content updates, a wide selection of JavaScript libraries, and great separation of concerns (SoS).

So why not to use CSR everywhere?

However, single page apps and client-side rendering are not all roses and they also have some pitfalls. Client side rendered apps are less SEO friendly, they require detailed and complex implementation, and they can ensure slower performance, though that also depends on your server.

Initial loading time is one of the key metrics and trigger points for web users. Lots of HTML elements are rendered through JavaScript and so users will observe a loading spinner or blank page for a few critical seconds before seeing the page content. Today there are dozens of studies proving a negative effect of slow website on users and revenue. As one of the examples, back in 2012 Twitter has moved its front-end performance to the server and dropped its initial page load times to 1/5th of what they had previously.

Related article: Gulp vs Grunt vs Webpack: Comparison of Build Tools / Task Runners

When do you need to render your applications on the server?

There are lots of things to consider, except for rendering speed or SEO. Moreover, the speed of rendering JavaScript SPAs can’t be called a determining factor, because if an app is correctly optimized and cached, then users will hardly notice a massive difference in performance. Both methods have their technical pros and cons that can later turn into a nice bonus or heavy burden, depending on each specific project.

However, if most of the rendering is done on the server, then there is the least reliance on client-side JavaScript and, as a result, fewer front-end issues to deal with (wider browsers’ compatibility, less code required, etc.). Besides, SSR may be a better option for clients with slow Internet to minimize the size and amount of requests needed to see the general content or users with outdated/no JavaScript engines.  Additionally, for mostly static sites, SSR may be the easy way out.

server-side-rendering-angular-application

What is Angular Universal and how does it make things easier?

Angular Universal is a library that deals with a number of issues and turns universal app development into a smooth experience. It allows developers to combine nimble performance and user involvement with full SEO and social media friendliness.

One more possibility offered is pre-rendering. Universal renders state and content on the server and allows users to run apps immediately. Yes, there is still an initial lag between the time plain HTML is presented to users and Angular gets involved on the front-end. But, during this time users can take some further steps, like clicking on something or typing on a search bar. With Universal Angularjs server side pre-rendering users’ events are tracked and played back once Angular comes into action.

However, what does it look like in terms of code? – In order to show server-side rendering in Angular 2 Universal, we will use one of our recent projects. It is a high-load marketplace application written with the use of Node.js, Angular 2 and MongoDB.

Related article: MongoDB vs MySQL Comparison: Which Database is Better?

Angular 2 server side rendering example: DA-14 use case

Running app in the browser:

// ./src/client.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { MainModule } from './browser.module';

export const platformRef = platformBrowserDynamic();

export function main() {
 return platformRef.bootstrapModule(MainModule);
}

switch (document.readyState) {
 case 'loading':
   document.addEventListener('DOMContentLoaded', () => main());
   break;
 case 'interactive':
 case 'complete':
 default:
   main();
}

The main function module:

// ./src/browser.module.ts
import { NgModule } from '@angular/core';
import { UniversalModule } from 'angular2-universal/browser';
import { AppModule } from './app/app.module’;
import { AppComponent } from './app/app.component';

export const isBrowser = true;
export const isNode = false;
export const APP_PROVIDERS = [
 {provide: 'isBrowser', useValue: isBrowser},
 {provide: 'isNode', useValue: isNode}
];

@NgModule({
 bootstrap: [AppComponent],
 imports: [
   UniversalModule,
   AppModule
 ],
 providers: [
   ...APP_PROVIDERS
 ]
})
export class MainModule {}

Running app on the server:

// ./src/server.ts
// Polyfills
import 'angular2-universal-polyfills';
import 'ts-helpers';

// Node modules
import * as path from 'path';
import * as express from 'express';
import * as bodyParser from 'body-parser';
import * as helmet from 'helmet';

// Angular
import { enableProdMode } from '@angular/core';
import { createEngine } from 'angular2-express-engine';

import { MainModule } from './node.module';

enableProdMode();

const app = express();
const ROOT = path.join(path.resolve(__dirname, '..'));
const PORT = process.env.PORT || 3000;

// Express views
app.engine('.html', createEngine({
 precompile: true,
 ngModule: MainModule
}));
app.set('views', path.join(ROOT, 'dist/client'));
app.set('view engine', 'html');

app.use(bodyParser.json());
app.use(helmet());

// Serve static files
app.use('/assets', express.static(path.join(__dirname, 'assets'), {maxAge: 30}));
app.use(express.static(path.join(ROOT, 'dist/client'), {index: false}));

// Routes with html5pushstate
app.get('*', (req, res) => res.render('index', {req, res}));

// Server
app.listen(PORT, () => {
 console.log(`Listening on: http://localhost:${server.address().port}`);
});

The main function module:

// ./src/node.module.ts
import { NgModule } from '@angular/core';
import { UniversalModule } from 'angular2-universal/node';
import { AppModule } from './app/app.module’;
import { AppComponent } from './app/app.component';

export const isBrowser = true;
export const isNode = false;

export const APP_PROVIDERS = [
 {provide: 'isBrowser', useValue: isBrowser},
 {provide: 'isNode', useValue: isNode}
];

@NgModule({
 bootstrap: [AppComponent],
 imports: [
   UniversalModule,
   AppModule
  ],
 providers: [
   ...APP_PROVIDERS
 ]
})
export class MainModule {}

Conclusion
Like any other technology or approach, Angular server side rendering will evolve and enhance over time. This very moment it offers comprehensive facilities for building search engine and mobile friendly applications with a great focus on user engagement and interactivity. 

↑ Go up

Similar post