Technical

SEO for Universal Angular 2.0

by on 6th June 2016

Universal Angular 2 Server Side Rendering for SEO & Crawl-Friendliness

There’s a lot of excitement around the release of Angular 2, for three reasons really:

  1. It’s been a long time coming (almost 2 years)
  2. The far more sane approach to modularity (component based UI)
  3. Server side rendering/universality

The last of these is what we’re going to be looking at here. Prior to Angular 2 (assuming you were using AngularJS) if you were hoping to have something that a search engine could understand, you’d have to follow the guidelines discussed here to fetch the output HTML and display that to a crawler instead of JS templates with no data.

The issues with that are fairly obvious – you can’t get meta data or content shown to a search engine, or a social crawler, which means no search rankings, and a poor social sharing experience. Fortunately, the requirement for that sort of system is now coming to an end. Angular 2 borrows a bunch of ideas from React, not least of which are the concept of component composed UI, and universal rendering with client-side JS pickup (see more on how React can be made to render server side for SEO here.)

Side Note

The main challenge with this until now has been a philosophical one. React starts with JS and makes HTML what comes out. Angular starts with the aim of making HTML, and adding JS to it. Once you really understand this, the reasons for the differences between the two become obvious.

Making an Angular 2 App Render Server Side

I’m going to expect familiarity with Angular 2 from here on, so if you’re not a developer, then be aware that here be monsters.

Let’s assume you’ve got an app basically up and running. The stack looks something like node, Express, Angular, gulp/grunt/broccoli/webpack/build chain of choice etc. If not, go to the Angular Universal quickstart guide and follow what it says. That will get you to a basic application which you can use.

The magic here is in Express having something to render beyond just the scaffold for Angular to fill in. With Angular 2 we can render entire pages on the server, with different data inserted based on the page, and therefore solve our no-data headaches. We do this with dependency injection.

Universal Header Template for Angular 2

At the top of your template component you’ll want to import and make available two objects, one called UniversalService, the other UniversalModel. We’ll get to what they look like later. Then in the head area, you’ll want to contain something like the following:

You’ll also need to tie the Universal service and model to that component. A basic version of that might look something like this:

UniversalService

The first part of then making that template work is a service which allows the data from our back end to pass to components. That’d look like this:

UniversalModel

The second part is creating a default model for our data:

Putting it All Together

Now when you come to create components for parts of your application, you can use your Universal Header template and inject values to the Universal Model like this:

Note that you can use the same principle to deal with authentication, checking for a logged in status and rendering different outcomes based on that flag. All you have to do is let the application know the user state, and it can then do different things based on that state value. We can also use this to render different blog posts in a CMS blog template, products in an ecommerce CMS and so on. Thanks to Angular’s adoption of DI, it becomes possible to render any conventional website on the server and deliver the page to the user ready to go.

Thanks to Johannes Werner for his work and inspiration for the code. For a demo Angular Universal application, take a look at his code here.

Like this? Sign up to read more

Responses

  1. Hey, thanks for the very interesting and informative article!
    I’m trying to run this code alongside the github Universal repo (https://github.com/angular/universal) – specifically the “todo” example – and unfortunately I’m getting the following error: Type ‘EventEmitter’ is not assignable to ‘EventEmitter’. Type ‘{}’ is not assignable to type ‘UniversalModel’. Property ‘title’ is missing in type ‘{}’.

    Any idea where this might be coming from?

Comments are closed.