BT

Three Development Patterns of Angular Universal

| by David Iffland Follow 4 Followers on May 04, 2016. Estimated reading time: 3 minutes |

While Angular is a powerful way to build web apps, developers have long known its limitations with SEO and accessibility. Sure, Google's crawler can execute JavaScript, but it's not the only crawler in the game. For example, after posting a link to Slack, its crawler will pull down a preview, but it doesn't execute JavaScript, so the raw Angular HTML templates show up in the preview. To eliminate the trouble this causes, Jeff Whelpley and Patrick Stapleton have worked on Angular Universal that allows the rendering to happen on the server.

The universal JavaScript technique (sometimes incorrectly referred to as "isomorphic") is not unique to Angular. Angular Universal works by doing an initial render of the app on the server, sending that to the browser for the user to see right away, and follows up with the client JavaScript. This is a slightly different order than typical Angular apps where the client JavaScript is sent and then the initial UI is rendered on the client.

Welpley and Stapleton have been working on Angular Unversal for over a year and have discovered six patterns that have popped-up over and over. They focused on three of those in their 2016 ng-conf session:

  1. Gap Events
  2. Async
  3. Dependencies

Gap Events are a side effect of the fact that rendering occurs on the server before the JavaScript client code is sent down to the browser. Depending on how fast that JavaScript code is sent down and processed, the user may interact with the UI before the code is ready to handle it. This gap can result in the loss of the user's interaction.

The solution to this problem is to record the user's events and replay them once the client JS has loaded. Here's a sample of what that code looks like:

var myEvents = [];
var myInputValue;

// record all keyup events on client view myInput
function recordEvents() {
  var $myInput = document.querySelector('.myInput')
  $myInput.addEventListener('keyup', function (event) {
    myEvents.push(event);
    myInputValue = event.target.value;
  });
}

// play back all keyup events on server view myInput
function replayEvents() {
  var $myInput = document.querySelector('.myInput');
  myEvents.forEach(function (event) {
    $myInput.dispatchEvent(event);
  });
  $myInput.value = myInputValue;
  $myInput.focus();
}

//  starting recording as soon as the window has loaded
window.addEventListener('load', recordEvents);

Rather making developers do this manually, Angular Universal uses a process called preboot to handle this work and it's enabled with a flag:

preboot: true

JavaScript is naturally asynchronous, but this can cause problems when trying to render Angular code on the server. The solution is often to use chaining or callbacks, but requiring developers to rewrite their code to solve the problem is not an option. "We can't do that. We have to figure out a way to handle all these disparate async events and coordinate when to send back the response," said Whelpley.

Angular Universal has another flag that solves the problem in one line:

async: true

Turning this flag on will use the new Zones feature of Angular to "track all async calls and know when they're resolved."

The third major problem with rendering Angular code on the server is the use of platform specific dependencies. For example, localStorage is a browser feature and doesn't exist on the server. Whelpley and Stapleton point to the use of Dependency Injection (DI) as the solution. Rather than using the platform features specifically, they recommend using DI to swap out the implementation depending on the context of code.

To developers used to testing their, this is no surprise. Whelpley pointed to testing and the other platforms that Angular runs on as proof that the technique will become prevalent in Angular 2 code. "We're pushing out platform specific dependencies to the edge. This pattern is the most powerful we've talked about today," said Whelpley.

The full video of the their ng-conf session is available now.

Rate this Article

Adoption Stage
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread
Community comments

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Discuss

Login to InfoQ to interact with what matters most to you.


Recover your password...

Follow

Follow your favorite topics and editors

Quick overview of most important highlights in the industry and on the site.

Like

More signal, less noise

Build your own feed by choosing topics you want to read about and editors you want to hear from.

Notifications

Stay up-to-date

Set up your notifications and don't miss out on content that matters to you

BT