前4大关键概念

The previous installation section goes over an example setup for Universal Apps, but it may be useful to look at things from a slightly different perspective. Below are the 4 key concepts you have to know and understand if you are building Universal Apps.

Polyfills

In both our server and client entry points, we have this at the very top:

import 'angular2-universal-polyfills';

What is this doing? Well, some of these are polyfills needed with most Angular apps:

import 'es6-promise';
import 'es6-shim';
import 'reflect-metadata';

The important part to be aware of is the Zone patch:


// for node:
require('zone.js/dist/zone-node.js');
require('zone.js/dist/long-stack-trace-zone');

// for browser:
require('zone.js/dist/zone.js');
require('zone.js/dist/long-stack-trace-zone');

There is a lot of magic going on here under the scenes, but basically the Zone patch makes sure Angular is aware of all async calls in your code. So, if you discover that your server side code is returning HTML before your http calls resolve, then more than likely you either don't have this patch referenced correctly OR you are making that http call via some async mechanism that is not in the patch.

One last thing to be aware of here. In some cases, you may want to patch DOM objects on the server side. For example, you want a window API to work on the server side. In most cases, we DON'T recommend you do this (use DI Swapping instead), but if you have to do this, then you would need to create your own patch and add it right after the reference to angular2-universal-polyfills.

Bootstrapping

As you should be aware from non-Universal Angular 2 development, you first need to bootstrap your app. The bootstrapping process is slightly different on the browser and node sides. At the very top level, there are some convenience functions that wrap a lot of low level functionality. It is possible to drop down a level to a more complex API, but at the high level, bootstrapping looks like this:


// browser side bootstrap:
platformRef.bootstrapModule(MainModule);

// node side bootstrap:
app.engine('.html', createEngine({}));
app.get('/*', (req, res) => {
  res.render('index', {
    req,
    res,
    ngModule: MainModule,
    preboot: false,
    baseUrl: '/',
    requestUrl: req.originalUrl,
    originUrl: 'http://localhost:3000'
  });
});

We will publish some documentation in the future of how to dive down a layer deeper in situation where you want more control over the bootsrap process on each side.

Server Context

A very common question is how to have control over the server side context to do things like server side redirects or to access data in the server request header. The key to doing any of this is to get access to the Express request and response objects in your code. As you can see, these objects are passed into the server side bootstrap:

app.get('/*', (req, res) => {
  res.render('index', {
    req,  // Express request object
    res,  // Express response object
    ngModule: MainModule,
    preboot: false,
    baseUrl: '/',
    requestUrl: req.originalUrl,
    originUrl: 'http://localhost:3000'
  });
});

All of these values are set on the Zone properties, so to access these values, you just need to call Zone.current.get('req') or change 'req' to whatever value you want. This API will be improved in the near future.

DI Swapping

The concept of DI Swapping is absolutely critical for Universal development. Basically, this is when you use Angular DI to abstract out code that needs to be specific for the browser or on the server. So, for example, if your code needs to access a value in the user's cookie, you would do something like this:

  • Create an abstract class interface Cookie that has an empty function get()
  • Create a browser-specific version called CookieBrowser in which the get() function where you reference window.document.cookie
  • Create a node-specific version called CookieNode in which the get() function where you reference Zone.current.get('req').cookies
  • In your browser NgModule, make sure you set CookieBrowser as a provider for Cookie
  • In your server NgModule, make sure you set CookieNode as a provider for Cookie

This is a really quick, high-level view of how DI Swapping works, but hopefully you get the idea. You can apply this same type of method anywhere in your code where you need platform-specific logic.

results matching ""

    No results matching ""