Angular 2 and Sitecore Best Practices

Angular 2 is out of beta and I have been using this for a while now to write single page applications in Sitecore. There are a couple of good blog posts around that describes how to get Angular 2 and Sitecore working. This post will focus on some touch points between Sitecore and Angular 2. The official Angular 2 site has a good article which describes setting up Angular 2 in Visual Studio 2015.

Retrieving data from Sitecore

Angular 2 has a HTTP library which makes it easy to work with JSON data returned from the server. Sitecore makes it easy to return JSON data especially from a controller action when using MVC.

However it seems like Sitecore.Services.Client is often overlooked when a restful API is required. Sitecore.Services.Client allows you to fetch Sitecore items in JSON format without writing any code, this link shows several ways to retrieve data this way. The Sitecore.Services.Client is also extensible just like almost everything else in Sitecore. The developer guide can be found here

PushState Routing

Angular 2 uses pushState routing by default, which means that the URL of the Angular route gets appended to the regular URL using a slash (/) as a separator just like Sitecore does. This is the preferred style and is good for SEO as well. An example of this would be an Angular 2 application that is hosted on mysite.com home page that has a route at mysite.com/details which will be displayed by Angular’s routing from the app on home page.

There will be an issue when someone tries to deep link into a mysite.com/details as Sitecore will try to resolve this item but cannot since this is only an Angular route not a Sitecore item. Perhaps the easiest way to solve this is by creating rewrite rules in IIS to resolve these links to the homepage. However I do not like this approach as it is not very maintainable. Creating the same app on a different page would require deploying additional rewrites. Instead I’m using below pipeline to detect this scenario and assign the correct item. Now the content author can add additional instances of the Angular 2 application without involvement from the development team:

using Sitecore;
using Sitecore.Diagnostics;
using Sitecore.Links;
using Sitecore.Pipelines.HttpRequest;
using System;

namespace Jeroen.Sitecore
{
    public class Angular2PushStateItemResolver : HttpRequestProcessor
    {
        public override void Process(HttpRequestArgs args)
        {
            Assert.ArgumentNotNull(args, "args");
            if (Context.Item == null && Context.Database != null && Context.Database.Name != "core")
            {
                //find all items that have the Angular app
                var query = string.Format("{0}//*[@@templateid='{1}']", args.StartPath, "<Guid of template with Angular 2 app>");
                var items = Context.Database.SelectItems(query);

                foreach (var item in items)
                {
                    var options = LinkManager.GetDefaultUrlOptions();
                    options.LanguageEmbedding = LanguageEmbedding.Never;

                    //check if this is an Angular component inside the current item and if so assign context item
                    if (args.LocalPath.StartsWith(LinkManager.GetItemUrl(item, options), StringComparison.OrdinalIgnoreCase))
                    {
                        Context.Item = item;
                        break;
                    }
                }
            }
        }
    }
}

Here is the code to include the pipeline:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <httpRequestBegin>
        <processor patch:after="*[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']" type="Jeroen.Sitecore.Angular2PushStateItemResolver, Jeroen.Sitecore" />
      </httpRequestBegin>
    </pipelines>
  </sitecore>
</configuration>

What about SEO, Social and performance?

Angular2 is rendering the page client side which can adversely affect a number of key areas:

  • Page performance as the browser needs to download and run a good amount of javascript to run the application. This can get especially troublesome in mobile and larger more complicated apps
  • SEO as search engine bots are not able to crawl the page
  • Social as Twitter, Facebook and other social media are not able to correctly display a preview

Angular Universal will address these issues by sending the rendered output to the client. This is currently only supported in node.js and ASP .NET core but should hopefully be available for ‘regular’ ASP .NET soon. Therefore I recommend keeping the best practices from the universal team in mind to ensure the application will work in Angular universal when this is ready. Maybe Angular Universal can even get the experience editor working?!