Why Angular Universal is Useful for SPA and SEO Friendly
Tags: beginners, javascript, angular, webdev
Published: 2019-11-01 16:15:43

<p align="justify">You can discover a lot of different forums and chats where Angular 6 is being discussed. There you can find answers to questions like how to build client applications or how to create SEO user-friendly interface. Surprisingly, but the most outstanding novelty recently occurred on the server-side.</p>

<p align="justify">And this is where Angular Universal appears. It is a revolutionary technology created for developing a totally new generation of Web and Angular mobile apps. This article is dedicated to highlighting its features!</p>

<p align="justify">Angular is a framework that sounds familiar to anyone who is close to the IT-sphere. Same can be said about Single Page Applications.
Actually, Angular Single Page Applications have a lot of potential benefits and here are some of them:</p>
<ul>
    <li><p align="justify">Smoother and faster UI as most resources HTML + CSS + Scripts are all loaded at once. Later on only that data will be loaded which is necessary for page rendering depends on user’s actions;</p></li>
    <li><p align="justify">SPA works here as a client side technology, HTML page is static while all the dynamic modifications happen in browser.  In earlier PHP, JSP, HTML was blended with server side logic and it was generated on the server. Server had to process more load.</p></li>
    </ul>

<p align="justify">Nevertheless, we are able to summarize it easily to the fact that Single Page Apps or SPAs supply a rather convenient User Interface performance and User Experience as well!</p>

<p align="justify">Taking into account all stated facts above, you may wonder why SPAs are not used by everyone if it provides such a high-quality user experience. Check below for the usage restraints.</p> 

## SPA in Angular: Downsides

<p align="justify">Firstly, it is impossible for a search engine to know certainly whether the web page is ready for processing or it is still in the process of rendering.  For example, the search engine can’t get the whole HTML because SPA loading can be still in the process or rendering is not done yet. Only after the MVC is taken into use the page becomes available for the search engine to render its data.</p>

<p align="justify">The stumbling block is that the engine has to be able to choose the right moment to scan or simply define when rendering is over. Otherwise, there is a huge possibility to index some content which is not ready for a user.</p>

<p align="justify">Furthermore, the complexity of indexation of SPA deep link is another important reason why SPAs are not so good in collaborating with search engines.</p>

<p align="justify">Support absence of HTML5 History in browsers led to a looking for an alternative, such as HTML bookmark anchors (/main#section2) for navigation between URLs. Despite it is hard to index pages separately for a searching engine there is still a set of approaches on how to do it. Nevertheless, plain HTML is always a better plan comparing to these approaches.</p>

<p align="justify">Moreover, the performance question still remains vital for SPA e.g. initial loading is slow. Many agree here that HTML-solution beats out SPA by several points, like speed (especially it concerns mobile phones) as SPA takes longer to start because of processing large JS amounts.</p>

## Google enhancements in terms of SPA

<p align="justify">The good news for us is that Google improved approach to indexing Single Page Applications. Thus, both reasons mentioned above can not be factually correct anymore. Moreover, the recent official shifting away from using IE9 leads to improving HTML5 History availability on most platforms.</p>

<p align="justify">In its order it makes implementing of URLs anchors not obligatory because simple URLs can be applied, such as /main/section2.</p> 

<p align="justify">Of course, it is a marvelous piece of news. Nevertheless, we should also take into account other search engines that handle an enormous amount of traffic, like Baidu that is popular in China, Yahoo or Bing so loved by Americans.</p>

<p align="justify">Mentioned above doesn’t look appealing for gaining loyal users for sure, though don’t go depressed too early. There is still a way to save the balance between navigation, optimization, and performance of SEO for single-page apps. It is SEO Angular Universal.</p>

## The sense of SEO Angular Universal

<p align="justify">To make a long story short, Angular Universal supplies you with the opportunity to create SEO-friendly, fast, and interactive sites  with all Single Page Apps benefits.</p>

## What is hidden behind ‘server-side rendering’

<p align="justify">Angular Universal functionality comprises something more than just providing markup rendering on the server-side. On the top of just rendering, you will get an Angular cut down version to generate required HTML on a side of the frontend. As a result, you will get an Angular SEO-friendly Single Page Application with faster launch time due to getting primary HTML payload from the server.</p>

## Case when user immediately begins to work  with an Angular SPA page

<p align="justify">There is some time in between rendering an initial HTML and taking Angular into effect to run as SPA. Angular Universal now provides a solution to cover the moment when the user begins triggering any event before Angular takes over. Such an event will be recorded and repeated. Server rendered event is recorded and repeat happens in SPA on the client-side.</p>

<p align="justify">One of the best tips is to start with the help of its official universal-starter. It will supply you with an application ready for performing that contains express server with  server-side rendering that works off the shelf.</p>

<p align="justify">Anyway, there are some common issues developers can get faced when dealing with the Angular Universal first project. Despite the fact, ‘it’s all out of the box’ there are still points you need to be aware of. Below a couple of code examples will be cited to demonstrate Angular Universal real cases and make life easier.</p> 

## Working differently on the client and on the server

<p align="justify">Usually we expect from our application to perform pretty much the same on both the client and the server-side without depending on APIs.</p>

<p align="justify">Unfortunately, the real-life is slightly different. Sometimes there is no opportunity to create such code that will perform the way we have described before. Moreover, we may have a set of actions we want them to act in different ways on the server and the client.</p> 

<p align="justify">For example, when external libraries that call DOM elements are needed to be used, the server-side process cannot access browser internal objects, as a result, it will cause errors. Let’s consider a case when Svg.js third-party library is in use. For sure, some expected errors will appear while building a project in SSR (server-side rendering) mode.</p> 

<p align="justify">To resolve them we’ve added a wrapper for this particular library which checks if the code is executed on client-side and allows access to library methods. This way we’ve avoided calling library methods from the server and got rid of build errors.</p>

```javascript
    import { Inject, Injectable, PLATFORM_ID } from '@angular/core';
    import { isPlatformBrowser } from '@angular/common';
    @Injectable()
    export class SvgService {
     private _svg: any;
     constructor(@Inject(PLATFORM_ID) private platformId: Object) {
       if (isPlatformBrowser(this.platformId)) {
         this._svg = require('svg.js');
       }
     }
     get(element) {
       if (isPlatformBrowser(this.platformId)) {
         return this._svg.get(element);
       }
     }
    }
```

<p align="justify">SPA has one index file which causes troubles when you need to add different titles and meta tags for different routes. It is also related to social media embedding when you want to show a preview after sharing the pages of your site in Facebook or Twitter.</p>
 
<p align="justify">To get around this problem we decided to create service that would dynamically add necessary meta tags for each page.</p>

<p align="justify">Service example:</p>

```javascript
    import { Injectable } from '@angular/core';
    import { Title, Meta } from '@angular/platform-browser';
    import * as seoConfig from '../../../assets/config/seo-config.json';
    @Injectable()
    export class SeoService {
     constructor(private titleService: Title, private meta: Meta) {}
     setMeta(page: string) {
       this.setTitle(seoConfig[page].title);
       this.setNameAttribute('description', seoConfig[page].description);
       this.setNameAttribute('keywords', seoConfig[page].keywords);
       this.setNameAttribute('twitter:title', seoConfig[page].title);
       this.setNameAttribute('twitter:description', seoConfig[page].description);
       this.setNameAttribute('twitter:image', seoConfig[page].image);
       this.setPropertyAttribute('og:title', seoConfig[page].title);
       this.setPropertyAttribute('og:description', seoConfig[page].description);
       this.setPropertyAttribute('og:url', seoConfig[page].url);
       this.setPropertyAttribute('og:image', seoConfig[page].image);
     }
     private setTitle(title: string) {
       return this.titleService.setTitle(title);
     }
     private setNameAttribute(attribute: string, value: string) {
       if (this.checkAttributeExist(attribute, 'name')) {
         this.meta.updateTag({name: attribute, content: value});
       } else {
         this.meta.addTag({name: attribute, content: value});
       }
     }
     private setPropertyAttribute(attribute: string, value: string) {
       if (this.checkAttributeExist(attribute, 'property')) {
         this.meta.updateTag({property: attribute, content: value});
       } else {
         this.meta.addTag({property: attribute, content: value});
       }
     }
     private checkAttributeExist(attribute: string, type: string) {
       return this.meta.getTag(`${type}="${attribute}"`);
     }

    }
```

<p align="justify">The component will then look like:</p>

```javascript
    import { SeoService } from '../core/services/seo.service';
    @Component({
     selector: 'app-home',
     templateUrl: './home.component.html',
     styleUrls: ['./home.component.scss']
    })
    export class HomeComponent {
     constructor(private seoService: SeoService) {
         this.seoService.setMeta('home');
     }
```

<p align="justify">Here is an example of seo-config.json file has been used:</p>

```javascript
    {
     "home": {
       "title": "2muchcoffee | Web and Mobile Application Development Company",
       "description": "2muchcoffee is top full-stack web and mobile app development company specializing in frontend and backend JS frameworks. Building cross-platform web, hybrid and native mobile applications for established businesses and MVP's for startups.",
       "keywords": "2muchcoffee, Angular, frontend, backend",
       "url": "https://2muchcoffee.com",
       "image": "/assets/img/content/opengraph/main.png"
     }
    }
```

##  Custom Angular directives in third-party libraries and consequences of their using 
 
<p align="justify">Usually developers use third-party services based on Angular functionality like custom directives, components, etc. Angular Flex layout can be stated here as an example for layouting.</p> 
 
<p align="justify">It can cause some unexpected issues that will affect user experience. After server-side rendering the document which client receives already includes <b>style</b> tags with its styles inside. However, @angular/flex-layout starts working only once Angular libraries are fully loaded.</p> 
 
<p align="justify">That should be done to provide proper operation of the mentioned directives. Depending on the network performance it can take several seconds from the time passed from the downloading of initial document till Angular taking over the doc.</p> 
 
<p align="justify">During this period a user may see the page that doesn’t include flex markup. Once Angular is started all blocks take their correct places but this causes flickering.</p>
 
<p align="justify">To resolve this UX problem we decided to refuse using @angular/flex-layout directives on the main page, and specified flex markup properties inside CSS file.</p>

## Conclusion

<p align="justify">The pros of the server-side rendering may expand through the times. Nevertheless, today it offers a great option for developing SPAs with its mobile versions that become Angular SEO-friendly Single Page Applications and are ready for convenient navigation and E-commerce websites with Angular.</p>

<p align="justify">So that is why we may say that now it is simpler to create various kinds of applications with Angular Universal and universal-starter to make your applications get indexed.</p>

Liked that? We’ve done our best! Go to our <u><a href="https://2muchcoffee.com/blog/"> blog </a></u>to find more useful articles.