Server-Side Rendering in Angular 2 with Angular Universal

Server-side rendering is a headache and if you ever worked with Angular 1, you should be worried about how Angular 2 plans to handle it. Server-side rendering in Angular 2 is often-times also called Universal.

You might often hear people say stuff like: "I am building an app that will be universal". What does that even mean?

Table of Contents

By default, front end frameworks have virtual DOM so when a hard request is made to an app built with such frameworks (like Angular), the expected behavior is weird. The request is served with a response of just the HTML content found at the entry point of the app while the main app content is lost.

This is not a problem to your users because your app virtually has content, styles, and state. Where the problem kicks in is with web crawlers that index your site for SEO sake. They get served with the incomplete HTML content which is very useless to them. This behavior even gets more painful when you expect people to share your app's link and you see an image like the one below when they do:

In Angular 1, if you tried to bind the app's title and description values using $rootScope you end up disappointed at how crawlers and social media robots see your site.

To replicate this challenge in Angular 2, I built an Angular 2 app with three routes (home, about and contact):

Preview

Source

<!--
This all you get as content
without server rendering
--><app-root>Loading...</app-root>

The conventional server rendering solution has saved us for years with Angular 1 by provisioning web crawlers with our actual content. That seemed to keep us happy but we were missing one thing -- state.

The Universal idea is to build an app that does not just render to server but also runs on the server. Running in the sense that our state, content and styles are intact on the client and the server as well. In Angular 2, this is achieved with the help of Angular Universal which loads our app on the server first, and then drops it to the browser once ready.

Free Node eBook

Build your first Node apps and learn server-side JavaScript.

📧

Thank you!

You have successfully joined the Scotchy super duper web dev awesome mailing list.

Angular Universal is the library the awesome Angular team is working on to make building universal apps a smooth experience. The library fixes a lot of nightmare we had working with Angular 1. As a matter of fact, our worst nightmare in Angular 1 is what Angular Universal takes away in Angular 2:

SEO Friendly

Angular Universal helps you to serve your app content to the server just as you did on the browser. When a web crawlers visit, they will be able to index you website's full content that can be used on search engines. This thereby solves one of the most popular front end challenges when working with JavaScript frameworks that create virtual DOM.

Social Media Friendly

With Angular Universal serving your sever with browser content, social media platforms that display brief information about your website when a link is added can get access to the needed details.

Pre-rendering

This is the most bind-blowing feature offered by Angular Universal. Angular Universal renders both your content and state as well as registering events on the server. The implication is that when your app boots, the server would serve the server-rendered content and a user can make use of the app at that stage.

The user's activities are recorded (with Preboot.js) at this stage and after couple of seconds when Angular is ready with the real thing, the user is automatically switched and those events replayed. The user won't even catch a glimpse of what is happening under the hood.

If you have been building Angular 2 app lately, you will see that the directory looks much alike to what we are used to. The key difference is the bootstrapping process. Bootstrapping Universal apps are done with a different library and in two different files (client.ts & server.ts).

Furthermore, we usually make use of platformBrowserDynamic to bootstrap but for Universal, we use platformUniversalLibrary from the Angular Universal library:

Universal is supported in Node and ASP.Net but coming to other backend platforms soon. We are using Node and to be precise to express server. The server uses the createEngine method to create a view engine that will deliver our Angular app content. The routes for each of the pages we need to render are handled as well. The rest of the code preps the express server.

The power of Universal comes from the fact that Angular abstracts DOM rendering. This is what makes Angular support for multi-platform possible. If you want Universal to keep working as expected, the you have to stay away from the DOM.

This does not mean that you cannot perform DOM operations but do not do that with the native solutions (document.domMethod() or $('dom-element')).