Ivy has been a name wandering the Angular universe for quite some time now, currently sitting at 93.46% of completion it is planned to be an opt-in option in Angular 8.0.0 planned to be released on April/March 2019.

So what exactly is Angular Ivy?

Angular Ivy is the code-name for the next version of the Angular rendering pipeline and view engine. It’s a complete refactor of the rendering with the intention to tackle 3 of the major issues with the current version:

  • Bundle size
  • Page loading speed
  • Debugging

Ivy will be the third version of the rendering pipeline on Angular, Angular 2 was shipped with the first version, while we’ve been using the current version Renderer2 since Angular 4, that focused on generating lesser code for Ahead-of-Time(AOT) compilations and thus increasing page speed and smaller bundles.

What changes

Incremental DOM

While until this point Angular has been using Virtual DOM(VDOM), which basically is a in-memory representation of the actual DOM through a Virtual Tree(VTree), allowing us to on state changes instead of directly updating the DOM, generate another VTree with the new representation that is checked against the old one and then by a process called Reconciliation find out the most efficient way to update the DOM.

Ivy brings this new method used internally at Google called Incremental DOM, which instead of creating a new VTree for each state change, compiles components to a set of instructions that are used to mutate templates in-place, resulting in reduced memory allocation, GC trashing, and better performance. You can find more regarding Incremental DOM in this article. Let’s give a look at how a component looks after compiling with Ivy.

Given this basic component:

// app.component.ts
import { Component } from  '@angular/core';
@Component({
selector:  'app-root',
template:  `
	<div class="hello">
		<h1>
			Hello from {{ app }}!
		</h1>
	</div>
`
})
export  class  AppComponent {
	app  =  'ivy-demo';
}

Is compiled into:

import { Component } from  '@angular/core';
import  *  as  i0  from  "@angular/core";
var  _c0  = [1, "hello"];
var  AppComponent  =  /** @class */ (function () {
function  AppComponent() {
	this.app  =  'ivy-demo';
}
AppComponent.ngComponentDef  =  i0.ɵdefineComponent({
	type:  AppComponent,
	selectors: [["app-root"]],
	factory:  function  AppComponent_Factory(t) {
		return  new (t  ||  AppComponent)();
	},
	consts:  3,
	vars:  1,
	template:  function  AppComponent_Template(rf, ctx) {
			if (rf  &  1) {
				i0.ɵelementStart(0, "div", _c0);
				i0.ɵelementStart(1, "h1");
				i0.ɵtext(2);
				i0.ɵelementEnd();
				i0.ɵelementEnd();
			} if (rf  &  2) {
				i0.ɵtextBinding(2, i0.ɵinterpolation1(" Hello from ", ctx.app, "! "));
			}
		}, encapsulation:  2
	});
	return  AppComponent;
}());
export { AppComponent };
/*@__PURE__*/  i0.ɵsetClassMetadata(AppComponent, [{
	type:  Component,
	args: [{
		selector:  'app-root',
		template:  "<div class=\"hello\">\n <h1>\n Hello from {{ app }}!\n </h1>\n </div>\n "
	}]
}], null, null);

So now the template function is a list of instructions that are used to create or update the component itself. These instructions became the own rendering engine as they no longer need to be passed by an interpreter. But let’s further analyze the template function. It receives two parameters:

The function is divided into two blocks defined by the bitwise operator rf: RenderFlags, the first acts upon component creation, while the latter is used every time change detection is called.

So, does this mean that every time change detection is called, the template is fully updated? No.
Given the previous example, let’s check what happens on:

i0.ɵtextBinding(2, i0.ɵinterpolation1(" Hello from ", ctx.app, "! "));

interpolation1 method gets the value and checks it against the previous state, emitting either the new value or a NO_CHANGE constant that is sent as an argument to the textBinding method that takes the value and updates the Tree if needed. This is one of the reasons why Incremental DOM results in so less memory allocation, no need of the extra DOM representation, thus no need to garbage collect the disposed one.
With this we can see how the pipeline changed from this:
flow1

To this:
flow2

Tree Shaking

First of all, what is Tree Shaking? Tree Shaking is a build step to remove unused code, up until this point there are third-party tools like Webpack, Rollup or UglifyJs that uses static analysis to determine which code to exclude. Angular 6 even brought us Tree Shakeable Providers, but Ivy brings this to a whole new level because as templates are transformed into instructions, Angular knows at compile time which instructions are not used and can remove them from the bundle. Given this principle they applied it to several features:

  • Template Syntax
  • Dependency Injection
  • Content Projection
  • Structural Directives
  • Life Cycle Hooks
  • Pipes
  • Queries
  • Listeners

Locality

Locality is a principle that the Angular Team had to simplify developer’s life. Basically, it means that each component should compile using only its own information. This becomes very handy with hot-reloading as it will only compile the component(s) you changed. As of now when you make a change on a Component, it not only re-build itself but also his parent because it also holds a copy of that information.
Another secondary effect of Locality is the ability to create Directives or Components at runtime.

Benchmarks

metrics1

metrics2

metrics3

Ivy in Angular 8.0

As stated at the beginning of the article, Ivy will be an opt-in option in Angular. For this and using Angular-CLI we can create a project using the following command:

ng new app-name --enable-ivy

For further information, you can check this tutorial provided by the Angular Team itself.

 

Written by Luís Mirandela | Senior Front End at Cleverti