Outputting faster and smaller bundles with AOT compilation
Angular Ivy is first and foremost an internal rewrite of the Angular compiler, the Angular runtime, and a few more pieces of the framework. A lot of effort was put into maintaining backward compatibility with application code written for the View Engine generation of the Angular framework (versions 4 through 8).
At the heart of this new generation is the Ivy Instruction Set, which is a runtime DOM instruction set similar to the Incremental DOM library by Google. In a nutshell, an Angular component is compiled into two lists of instructions that, when executed by Ivy, will initialize the DOM with the first list of instructions and update the DOM with the second list of instructions whenever changes are detected.
The Ivy Instruction Set is lighter than the View Engine equivalent, which the runtime had to translate before applying it. In View Engine, it used to be the case that a large Angular application would eventually have a smaller just-in-time (JIT)-compiled bundle than the AOT-compiled bundle for the same application. With Ivy, this is no longer the case.
For small Angular applications, Ivy adds the benefit that the Ivy Instruction Set and the individual parts of the runtime are tree-shakable. This means that we are not paying for the parts of the framework runtime that we are not using, in that they are removed from the output bundle—for example, Angular's animation and globalization APIs are not part of our application bundle unless we are using them. This is very important in microfrontends and web components, where we need to minimize the overhead of the Angular framework.
Angular version 11 is the final major version supporting View Engine. The Ivy Instruction Set is kept as a code-generation API, meaning that our code should not rely on it. Angular libraries supporting Angular versions 9-11 are not recommended to ship Ivy-compiled code. Instead, the Angular Compatibility Compiler is used to transpile View Engine-compiled libraries to Ivy. Unfortunately, this means that our initial build time increases as the Angular Compatibility Compiler must compile each Angular library entry point in our node_modules
folder. This is especially hard to manage in managed build pipelines.
Read about the Angular Compatibility Compiler in Chapter 10, Using the Angular Compatibility Compiler.
As of Angular version 12, it is recommended for Angular libraries to ship partially Ivy-compiled bundles using the Ivy compiler. This means that our application can more fully enjoy incremental builds that speed up the overall build time. This is because of an Ivy concept known as the principle of locality. The Ivy compiler only needs to know about the public API of, for example, child components rather than having to know about their injected dependencies and mention them in the compiled output of the parent component.
In general, Ivy results in decreased build time, except for the time it takes to run the Angular Compatibility Compiler on Angular libraries, including the Angular framework's packages.
As we discussed, using the Ivy compiler also results in decreased bundle sizes overall. However, if we are using most parts of the framework runtime, our main chunk's bundle size might increase while the size of lazy-loaded chunks decreases.
With the introduction of Angular Ivy, we can now use AOT compilation during all phases of development. This removes subtle but important differences between development, testing, the build process, and production runtime.
The short explanation in this section is just enough to give us an overall idea about the effect that AOT compilation has on Angular applications. However, this book is a practical approach to developing Angular Ivy applications. In everyday development, we do not have to be familiar with the internals of the Angular compiler, rendering engine, and runtime.
Read more about the impact and limitations of Angular's AOT compiler in Chapter 12, Embracing Ahead-of-Time Compilation.
In the following section, we look at the compilation presets and configurations introduced by Ivy and its accompanying TypeScript versions.