Bootstrap Angular 2 with Ahead of Time Template Compilation

Angular 2 has several different paradigms for bootstrapping an application. The default platform that is used in Angular’s examples is the dynamic browser platform. Platform browser means that this application is going to be bootstrapped in a browser and will therefore have direct access to the DOM and other browser APIs. Dynamic means that your Angular templates are going to be compiled dynamically as part of the bootstrap process. While using this platform for development is fine, the dynamic platform should not be used in production. Here at Lucidchart we improved our load times by five seconds in our beta editor by switching from the dynamic platform. The solution we used to bootstrap Angular 2 was to use Ahead of Time (AOT) template compilation with the browser platform. There is also a webworker platform and a server platform.

This tutorial assumes that you already have an Angular 2 project set up. If you don’t, you should check out our previous tutorial on how to install an Angular 2 application. In your application, you will have bootstrap file. If you set up your application with Angular-CLI, it will be called main.ts and will look like this:

import './polyfills.ts';

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
import { AppModule } from './app/';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule);

In looking at this file, we can see a few different things happening. All of the poyfills required to run Angular 2 are imported from the core-js and zone node modules. Then platformBrowserDynamic is imported from @angular/platform-browser-dynamic. This is fine for development, but it is much better to compile your templates once and then serve the pre-compiled templates to your users. In order to precompile your templates, you’ll need to update your bootstrap logic. Here is a diff of the changes you’ll need to make:

-import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+import { platformBrowser } from '@angular/platform-browser';
 import { enableProdMode } from '@angular/core';
 import { environment } from './environments/environment';
-import { AppModule } from './app/';
+import { AppModuleNgFactory } from './app/app.module.ngfactory';
 
 if (environment.production) {
   enableProdMode();
 }
 
-platformBrowserDynamic().bootstrapModule(AppModule);
+platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);

And here is the resulting file:

import './polyfills.ts';

import { platformBrowser } from '@angular/platform-browser';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
import { AppModuleNgFactory } from './app/app.module.ngfactory';

if (environment.production) {
  enableProdMode();
}

platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);

Two things changed here. We removed dynamic from our platform browser import, and we also imported and bootstrapped AppModuleNgFactory instead of AppModule. AppModuleNgFactory is a TypeScript class that is generated by the compiler to create your application. When the dynamic platform is used, this factory is created each time you load your application; however, now we are creating it before our application even runs. The AppModuleNgFactory is not going to exist until you build your application with ngc. If you try to build your application with ng build or tsc, you’ll get an error like this:

ERROR in ./src/main.ts
Module not found: Error: Can't resolve './app/app.ngfactory' in 
 @ ./src/main.ts 5:0-57
 @ multi main

It is likely that ngc was installed with your angular application, so in order to run ngc, you’ll just have to run ./path/to/node_modules/.bin/ngc -p ./path/to/src in your project directory. If it’s not installed, you can install it with npm install @angular/compiler-cli typescript@next @angular/platform-server @angular/compiler.

After successfully running ngc, you’ll see that you have a main.js in your project’s output directory. You’ll notice that it outputs es6 and does not package it, so you’ll have to use another tool to package your es6. My colleague set up an example application that uses Google Closure Compiler to package an Angular application with AOT template compilation for production and Just in Time (JIT) template compilation for development. He also wrote a blog post about his endeavors that you can find here.

There you have it — everything you need to successfully bootstrap an Angular 2 application with Ahead of Time template compilation.

No Comments, Be The First!

Your email address will not be published.