Multiple solutions for Angular Ahead of Time (AOT) Compilation

When we started developing new applications at Emarsys in the early stages of Angular (2 beta), the first thing we noticed is the growing size and slowing speed of the application. The size of the unminified source code quickly grew above 3 Mbs and took multiple seconds just to become responsive.

 

Just-in-Time (JIT) compilation

The main reason for this was that we were using JIT compilation. It creates a performance penalty by parsing the component templates every time the user opens the web page. The parsing also needs the compiler bundled into the application. It is the part that transforms HTML templates into runnable code. The compiler can take up half of the bundled code size, which is a huge portion.

 
Just-in-Time (JIT) compilation

We generate the source code at build time and JIT compilation starts to parse the templates at run time. Only after this can the application start with the generated code.

Ahead-of-Time (AOT) compilation

We can cope with this performance penalty if we move the compilation out of the run time (browser) to the source code generation. It statically analyzes and compiles our templates at build time.

 
Ahead-of-Time (AOT) compilation

This way compilation happens only once at build time and we no longer need to ship the Angular compiler and the HTML templates into the bundle. The generated source code can start running just after downloaded into the browser, no previous steps are needed.

The AOT compilation turns this HTML template

into this runnable code fragment

Benefits of AOT compilation

  • Smaller application size (Angular compiler excluded)
  • Faster component rendering (already compiled templates)
  • Template parse errors detected earlier (at build time)
  • More secure (no need to evaluate templates dynamically)

For AOT compilation we need some tools to accomplish it automatically in our build process. Currently two solid solutions exist. Both methods work, but they serve different purposes and have different advantages and disadvantages.

Solution 1: ngc command line tool

The ngc command line tool comes with the package @angular/compiler-cli. It is a wrapper around the Typescript compiler (tsc). You can specify the files to be compiled within tsconfig.json with the files and excludes field. Compiler specific options can be placed inside the angularCompilerOptions property.

When running ngc, it searches for the entry module (it gives the context to the compilation) and the corresponding components, directives and pipes. For every one of them it compiles and outputs an .ngfactory.ts suffixed Typescript file where the compiled templates reside. The compiled files are generated next to the original file by default. The destination can be modified by genDirinside angularCompilerOptions.

It also generates the transpiled files from Typescript to Javascript besides the compiled factory files. These files represent the uncompiled Typescript files with the description of the original classes next to them in a .metadata.jsonsuffixed file. These files are not needed to run the application in AOT mode. They only come in handy when building an Angular library that supports AOT compilation.

To use the newly generated files, we will have to change the bootstrap of the application.

We need to change the module file to the .ngfactory.ts suffixed one
and import the bootstrap from @angular/platform-browser. The @angular/platform-browser doesn’t include the compiler, making a huge gain in file size.

After generating the AOT compiled Typescript files another step is needed where we bundle the application.

Advantages

  • It can always be used with the newest version of Angular just after it has been released
  • After compilation any kind of bundling tool can be used
  • Outputs metadata files for library development

Disadvantages

  • Only supports HTML in templates and CSS in styles.
  • No watch mode yet
  • Need to maintain AOT version of the bootstrap file

Example repositories

Solution 2: @ngtools/webpack plugin

The next package @ngtools/webpack is a plugin for Webpack 2 published as part of the Angular CLI repository. It gives a loader and a plugin to set up the configuration.

The plugin needs the location of the Typescript configuration and the entry module of the application. The entryModule property consists of the file path and the exported module class divided by a hashmark. With these it can run the AOT compiler and generate the factory files.

One big difference here is that it won’t transfer the factory, metadata and transpiled JIT Javascript files to the filesystem. It will only bundle the application based on the factory files, which only exist inside Webpack’s memory filesystem. It also searches for the entry point and transforms the bootstrap file automatically to become suitable for AOT compiled files.

The loader inside the rules property enables to use any kind of file type inside the component’s decorator templateUrl and styleUrls property.
For example SCSSLESS for stylesheets and PUG for templates. It replaces the relative URLs in templateUrl and styleUrls to require statements. Also lazy loaded modules on routes transpiled to import statements and the sub-modules are also AOT compiled with the main application.

This loader basically does the job of awesome-typescript-loader + angular-router-loader + angular2-template-loader and adds AOT compilation to the chain.

Advantages

  • Custom file types available for templates and styles through Webpack loaders (SCSS, PUG,…)
  • No separate process for compilation
  • Watch mode for AOT compiled files
  • No need to maintain AOT version of bootstrap file
  • No output to disk for separate *.ngfactory.ts files

Disadvantages

  • Can only be used with Webpack 2
  • Need to wait for new versions after Angular release to Angular CLI repository catch up
  • Compatible with current version
  • Not good for AOT compatible package publishing, because it doesn’t output separate compiled files

Example repositories

Solution 3: @ultimate/aot-loader plugin

A brand new Webpack 2 plugin (currently in beta) backed by the team behind Ultimate Angular. It gives a loader and a plugin to set up the configuration.

@ultimate/aot-loader is very similar in configuration and in abilities to the Angular CLI plugin. The factory and metadata files are only generated to the memory file system. The entry point is also transformed to load the factory files instead of the regular ones. Lazy loaded modules are transpiled and split into different chunks apart from the main bundle.

Loaders inside rules enable us to write templates and styles of components in the desired extension (SCSS, PUG, etc.).

Advantages

  • Same advantages as for the Angular CLI package
  • Compatible with Angular 4

Disadvantages

  • Can only be used with Webpack 2
  • Not good for AOT compatible package publishing, because it doesn’t output separate compiled files

Example repositories

Summary

It doesn’t matter which solution you choose, your application can greatly benefit from AOT compilation through size and speed. It halves the size of a small to medium sized application and multiplies it’s start up speed. If you are only using HTML for templates and CSS for styles or using a different build system from Webpack or developing a package in Angular 2, ngc can be a good fit. Otherwise I would stick with the @ngtools/webpack or the @ultimate/aot-loader plugin and enjoy it’s benefits over the command line solution.

If you want to dive deeper into AOT compilation, you can read the official documentation also.

Special thanks to Wassim Chegham for the images about AOT and JIT compilation.

This post originally appeared on the Emarsys Craftlab blog.