Angular server-side rendering with @ng-toolkit/universal

Introduce server-side rendering with @ng-toolkit/universal, and make it readable for search engine robots.

SPA pitfall — SEO

Most of the Single Page Applications have one big problem. They are rendering and working on the client side. Now you can shout at me: “Hey! This is an advantage, not pitfall!”. And you are completely right. The problem starts when your application renders ONLY on the client side.

How crawlers explores the web?

The problem is that search engine robots/crawlers work similar to the curl command. Why? Launching browser and executing JavaScript is an expensive task. There is no time and resources to do that when you need to search thousands of pages.

Let’s create an angular app and check, how robots see it:

ng new myApp

cd myApp

ng serve

Now in the other terminal window execute curl command and take a look at the output:

$ curl localhost:4200 <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>MyApp</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> </head> <body> <app-root></app-root> <script type="text/javascript" src="runtime.js"></script><script type="text/javascript" src="polyfills.js"></script><script type="text/javascript" src="styles.js"></script><script type="text/javascript" src="vendor.js"></script><script type="text/javascript" src="main.js"></script></body> </html>

Do you see the problem? What we got inside <body> ? Nothing. App bootstrap node; and some JavaScript. How can we solve it?

Server-side rendering (Angular Universal)

The solution is Angular Universal. An Angular extension for nodeJS, which launches the application on the server and generate full HTML response depending on income request. Now, the flow from the user request, to the rendered and interactive web app, looks like that:

User requests the page The request comes to the server NodeJS generate HTML and send it to the browser The browser renders the view from the HTML and immediately displays it to the user, simultaneously JavaScript is being executed When JavaScript finishes bootstrap of the app, it changes the HTML-rendered view with the Angular App The user sees fully interactive Angular Application

Ok. We know the theory. Let’s go with practice now. You can go forward with the guide from Angular Universal creators then you will probably end with the Universal Starter repository.

Angular 6 is released, with new great CLI tools, and they propose me to make a manual setup or start with the boilerplate? Give me other solution!

@ng-toolkit/universal — one command to add Angular Universal to any project

That’s where @ng-toolkit/universal comes into the game. Type one simple command:

ng add @ng-toolkit/universal

And boom! You got it! The whole setup is done for you!

Let’s launch the app:

npm run build:prod

npm run server

And check the curl comand in separate terminal window:

$ curl localhost:8080

<!DOCTYPE html><html lang="en"><head> <meta charset="utf-8"> <title>MyApp</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="stylesheet" href="styles.34c57ab7888ec1573f9c.css"><style ng-transition="app-root"></style></head> <body> <app-root _nghost-c0="" ng-version="6.0.3"><div _ngcontent-c0="" style="text-align:center"><h1 _ngcontent-c0=""> Welcome to app! </h1><img _ngcontent-c0="" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==" width="300"></div><h2 _ngcontent-c0="">Here are some links to help you start: </h2><ul _ngcontent-c0=""><li _ngcontent-c0=""><h2 _ngcontent-c0=""><a _ngcontent-c0="" href="https://angular.io/tutorial" rel="noopener" target="_blank">Tour of Heroes</a></h2></li><li _ngcontent-c0=""><h2 _ngcontent-c0=""><a _ngcontent-c0="" href="https://github.com/angular/angular-cli/wiki" rel="noopener" target="_blank">CLI Documentation</a></h2></li><li _ngcontent-c0=""><h2 _ngcontent-c0=""><a _ngcontent-c0="" href="https://blog.angular.io/" rel="noopener" target="_blank">Angular blog</a></h2></li></ul></app-root> <script type="text/javascript" src="runtime.a66f828dca56eeb90e02.js"></script><script type="text/javascript" src="polyfills.2f4a59095805af02bd79.js"></script><script type="text/javascript" src="main.178573f0f1b826344a91.js"></script> <script id="app-root-state" type="application/json">{}</script></body></html>

Better? Much better! Now search engine robots sees that your app have some content!