slides:  bit.ly/jsheroes-ivy

Andrei Antal

@andrei_antal

  • frontend engineer, since i can remember
  • currently doing consulting and training @JSLeague
  • web & JS technologies enthusiast
  • UX and accessibility passionate
  • perpetual learner

Frontend Developer

organizer for ngBucharest

@ngBucharest

groups/angularjs.bucharest

Noh, servus!

Upcoming events

8 - 9 October 2020, Timisoara

Angular 9 is out!

What's new in Angular 9?

  • Ivy - now enabled by default in new projects (was opt-in for v8) 
    • New rendering engine replacing ViewEngine (more on that in just a minute)
    • Smaller builds

Smaller bundle sizes

Smaller bundle sizes

Smaller bundle sizes

What's new in Angular 9?

  • Ivy - now enabled by default in new projects (was opt-in for v8) 
    • New rendering engine replacing ViewEngine (more on that in just a minute)
    • Smaller builds
  • Strict template checking and language service improvements (DEMO)
  • New options for providedIn

What's new in Angular 9?

@Injectable({
  providedIn: "root" | "any" | "platform"
})
export class MyService {}

What's new in Angular 9?

  • Ivy - now enabled by default in new projects (was opt-in for v8) 
    • New rendering engine replacing ViewEngine (more on that in just a minute)
    • Smaller builds
  • Strict template checking and language service improvements (DEMO)
  • New options for providedIn
  • @ViewChild(...{static: false}) not needed - the default
  • TypeScript 3.7 support
  • Testing improvements (DEMO)
  • New in browser debugging capabilities (DEMO)

How to upgrade?

ng update @angular/core @angular/cli

Ivy

Ivy

[brief] History of Angular

  • Angular 2 (2016)
    • Renderer v1 - Template Compiler
    • NgModules

 

  • Angular 4 (2017)
    • ​Animations and HttpClient
    • Renderer v2 - ViewEngine

 

  • Angular 8 (2019)
    • ​Diferential loading
    • Renderer v3 - Ivy - preview mode

Why a compiler?

Angular templates (declarative)

JavaScript code that runs in the browser

compilation

@Component({
 selector: ‘app-component’
 template:
    '<h1>{{ title }}</h1>'
})
export class AppCmp {
title = "hello";
}
export class AppCmp {
  title: string;

  ngComponentDef 
    = ng.defineComponent({...})
}

ngc

  • transform Angular abstractions
  • create and manipulate DOM
  • bindings and change detection
  • css and animations

Why a compiler?

Angular Compiler

Angular Runtime

(not shipped with your final bundle when using AOT)

Evolution - Template Compiler

Evolution - ViewEngine

Evolution - Ivy

ViewEngine pipeline

app.component.ts

app.component.html

app.component.(s)css

app.component.js

app.component.ngfactory.js

app.component.metadata.json

app.component.ngsummary.json

ViewEngine compiler

ViewEngine compiler

Tree shaking

// moduleA.js

export function f1() {
  ...
}

export function f2() {
  ...
}


// main.js

import { f1 } from './moduleA.js';

f1();

Only f1 is included in the final bundle

// moduleA.js

export function f1() {
  ...
}

export function f2() {
  ...
}


// main.js

import { f1 } from './moduleA.js';

f1();

if(condition) {
  f2();
}

Both f1 and f2 are included in the bundle

Ivy pipeline

app.component.ts

app.component.html

app.component.(s)css

app.component.js

No more ngfactory files!

Ivy compilation

@Component({
  selector: 'app',
  template: `<h1>{{title}}</h1>`
})
class AppComponent {
  title="Ivy Renderer";
}
var AppComponent = (function () {
  AppComponent.ngComponentDef = defineComponent({
    type: AppComponent,
    selectors: [["app-root"]],
    consts: 2,
    vars: 1,
    template: function AppComponent_Template(renderFlags, ctx) {
      if (renderFlags & RenderFlags.Create) {
        elementStart(0, "h1");
        text(1);
        elementEnd();
      } if (renderFlags & RenderFlags.Update) {
        textBinding(1, interpolation1("", ctx.title, ""));
      }
    }, 
    encapsulation: 2
  });
}());

creation phase

update/change phase

AppComponent.ngComponentDef.template(create, app)

Ivy compilation

AppComponent

UserComponent

WidgetComponent

AppComponent.ngComponentDef.template(create, app)
UserComponent.ngComponentDef.template(create, user)
WidtgetComponent.ngComponentDef.template(create, widget)

Ivy compilation

  • Create instructions

 

element()

text()

template()

elementContainer()

projection()

listener()

pipe()

i18n()

...

  • Update instructions

 

property()

attribute()

styleProp()

classProp()

hostProperty()

pipeBind()

textInterpolate1-8()

pureFunction1-8()

...

Ivy compilation

Ivy compilation

Ivy compilation

Ivy - tree shakable

  • Ivy instruction

 

Angular

export function elementStart() { ... }


export function text() { ... }


export function attribute() { ... }
elementStart()


text()


attribute()
  • Component definition calls the Framework

// other unused Angular features -> tree-shaken

...

Incremental vs Virtual DOM

  • Virtual DOM

Incremental vs Virtual DOM

  • Incremental DOM

Locality

  • Faster compilation times:
    • ViewEngine requires a global static analysis of the entire application
    • In Ivy:
      • Compiling a component/directive etc. only requires local information
      • Recompiling (due to change) should not trigger recompilation of the dependencies

Locality

<div>
  <span>{{title}}</span>
  <child-component *ngIf="show"></child-component>
</div>
function View_RootCmp_0(_l) {
  return ng.ɵvid(0, [
    (_l()(), ng.ɵeld(0, 0, null, null, 4, "div", [], null, null, null, null, null)),
	(_l()(), ng.ɵeld(1, 0, null, null, 1, "span", [], null, null, null, null, null)),
	(_l()(), ng.ɵted(2, null, ["", ""])),
	(_l()(), ng.ɵand(16777216, null, null, 1, null, View_RootCmp_1)),
	ng.ɵdid(4, 16384, null, 0, ng.NgIf, [ng.ViewContainerRef, ng.TemplateRef], {ngIf: [0, "ngIf"]}, null)
  ], );
}

ViewEngine - non-locality

Locality

<div>
  <span>{{title}}</span>
  <child-component *ngIf="show"></child-component>
</div>
function RootCmp_Template(rf, ctx) {
  if (rf & 1) {
    ng.ɵelementStart(0, "div");
    ng.ɵelementStart(1, "span");
    ng.ɵtext(2);
    ng.ɵelementEnd();
    ng.ɵtemplate(3, RootCmp_child_cmp_Template_3, 1, 0, null, [1, "ngIf"]);
    ng.ɵelementEnd();
  } if (rf & 2) {
    ng.ɵtextBinding(2, ng.ɵinterpolation1("",
    ctx.title, ""));
    ng.ɵelementProperty(3, "ngIf", ng.ɵbind(ctx.show));
  }
}

Ivy - locality

NgIf.ngDirectiveDef = i0.ɵdefineDirective({
  factory: function NgIf_Factory(t) {
    return new NgIf(
      i0.ɵinject(ViewContainerRef),
      i0.ɵinject(TemplateRef)
    );
  },
  ...
});

A look into the future of Angular

WARNING! Experimental APIs

(do try this at home)

Code repo:

Module-less component

and

zone-less change detection

 

branch: 1-render_single_component

branch: 2-moduless-component-and-zoneless-change-detection

Lazy load components

branch: 3-lazy-load-components

Higher-order components

branch: 4-higher-order-components

Thank you!

JSHeroes - Angular 9 Ivy

By Andrei Antal

JSHeroes - Angular 9 Ivy

A look at Angular Ivy, the new rendering engine in v9. JSHeroes meetup, April 2020

  • 2,167