Slide 1

Slide 1 text

Recap Theory of Ivy Angular Meetup NOV 2018 Siwat Kaolueng @perjerz3434

Slide 2

Slide 2 text

Siwat Kaolueng - Angular & Web & Front-end Enthusiast - Freelancer - Angular Thailand Organizer

Slide 3

Slide 3 text

Angular has two parts - Angular Renderer - Code that we generate when your ngc AOT compiler against your template - NgFactory File - Angular code import from core, browser support compile at runtime - Runtime - Angular gets a lot of feedback from companies, developer relations and so on. - They want Angular to be simpler, easier to pick up and understand, build faster, smaller bundles and advance features such as HOC. - Current rendering architecture (View Engine) is limited. - Ivy is new back-end for compiler with new runtime. - Backward Compatible with View Engine 4.0

Slide 4

Slide 4 text

Ivy simplify internal Angular - Compilation - How we compile the app - Deployment - How we package bundle and shipping libraries on npm - Dependency - Link to together and depend on each other at runtime

Slide 5

Slide 5 text

Goals Optimizability → pay as you go both you template code and runtime code Incrementality → faster compilation, simpler libraries reduce complex meta data on NPM Flexibility → more powerful foundation new features

Slide 6

Slide 6 text

History Template Compiler 2.0 → View Engine 4.0+ → Ivy ???

Slide 7

Slide 7 text

Example Template
{{title}}

Slide 8

Slide 8 text

2.0 Template Compiler ( 2 years ago) Imperative List of Operation NgFactory per @Component, @NgModule Templates → DOM calls Generate fast, optimized code

Slide 9

Slide 9 text

Compiled with Angular 2.0 const parentRenderNode:any = this.renderer.createViewRoot(this.parentElement); this._text_0 = this.renderer.createText(parentRenderNode,'\n ',null); this._el_1 = ng.createRenderElement(this.renderer,parentRenderNode,'div',ng.EMPTY_INLINE_ARRAY,null); this._text_2 = this.renderer.createText(this._el_1,'\n ',null); this._el_3 = ng.createRenderElement(this.renderer,this._el_1,'span',ng.EMPTY_INLINE_ARRAY,null); this._text_4 = this.renderer.createText(this._el_3,'',null); this._text_5 = this.renderer.createText(this._el_1,'\n ',null); this._anchor_6 = this.renderer.createTemplateAnchor(this._el_1,null); this._vc_6 = new ng.ViewContainer(6,1,this,this._anchor_6); this._TemplateRef_6_5 = new ng.TemplateRef_(this,6,this._anchor_6); this._NgIf_6_6 = new ng.Wrapper_NgIf(this._vc_6.vcRef,this._TemplateRef_6_5); this._text_7 = this.renderer.createText(this._el_1,'\n',null); this._text_8 = this.renderer.createText(parentRenderNode,'\n',null); From research → One of the fastest way to create dom structure in the browser Get feedback → Too verbose, Too many bytes, Too much overhead to bundles Different Approach to represent template with less overhead -> View Engine 4.0

Slide 10

Slide 10 text

4.0+ View Engine Instead of rendering instructions, generate a data structure Data structure is interpreted at runtime Generate small, optimal structures (optimize template size and not to sacrifice performance during rendering)

Slide 11

Slide 11 text

Compile with Angular 7.0 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) ], ...); } Smaller, harder to understand (magic number & null) General Idea - div, span , nextline text node, child component, ngIf control child component

Slide 12

Slide 12 text

Ivy replace View Engine while remaining backwards compatible Hundred of hundreds of Angular apps at Google process of testing Ivy (thousands tests each) not only internal test suite

Slide 13

Slide 13 text

Architecture

Slide 14

Slide 14 text

Annotations → Static Fields @Component → ngComponentDef @Directive → ngDirectiveDef @Injectable → ngInjectableDef Used to be produced in separate NgFactory files Move into component and directives or classes itself

Slide 15

Slide 15 text

@Component({ selector: 'root-cmp', template: `
{{title}}
`, }) export class RootCmp { … } export class RootCmp { … } RootCmp.ngComponentDef = ng.ɵdefineComponent({ type: RootCmp, selectors: [["test-cmp"]], consts: 4, vars: 2, factory: function RootCmp_Factory(t) { return new (t || RootCmp)(); }, directives: [ChildCmp, ng.NgIf], template: function RootCmp_Template(rf, ctx) { … }, }); Your code Compiled by Ivy Static Field Contain metadata - tell ivy about information about component such as selector, two directives child component, ngIf Template Function - rendering template DOM & Change Detection

Slide 16

Slide 16 text

Template Function
{{title}}
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)); } } Imperative calls like Template Compiler 2.0 Create div, span, child template with ngIf First if block render the first time insert into DOM Second block run change detection, running two binding interpolation and condition for ngIf

Slide 17

Slide 17 text

Ivy templates use a new Instruction Set instead of single template interpreter at runtime in View Engine

Slide 18

Slide 18 text

Ivy Instruction Set DOM creation Data binding Change detection i18n Queries Dependency Injection Styling Containers Templates Content Projection Pipes SVG

Slide 19

Slide 19 text

Example Service @Injectable() export class AuthGuard { constructor( router: Router, http: HttpClient, @Inject(CONFIG) config: any, ) { … } } - Auth Guard check when navigate in - Injecting Router, HTTPClient, config object - Check permission in config for current url → HttpClient calls for user permission → router navigate away if no permission - In Ivy @Injectable -> ngInjectableDef

Slide 20

Slide 20 text

Injectable() xport class AuthGuard { constructor( router: Router, http: HttpClient, @Inject(CONFIG) config: any, AuthGuard.ngInjectableDef = ng.ɵdefineInjectable({ factory: function AuthGuard_Factory() { return new AuthGuard( ng.ɵinject(Router), ng.ɵinject(HttpClient), ng.ɵinject(CONFIG), - ngInjectableDef has factory function. Factory function is to create the instance. - For every dependency needing to be injected. Factory function call ivy inject instruction. Give token and get back instance of the dependency - Once those instances have been created factory function calls constructor. - If no dependency, no inject instruction

Slide 21

Slide 21 text

Benefits Optimizability Incrementality Flexibility

Slide 22

Slide 22 text

Optimizability Don’t pay (in bytes) for unused framework features Achieved via tree-shaking Ivy let us leverage a JS tools that optimize code especially Tree Shaking. Not use feature in app, don’t pay the cost of bytes at runtime

Slide 23

Slide 23 text

Tree Shaking aka dead code elimination aka live code inclusion Optimizer looks to prove a certain code is not used at runtime, and remove the code from bundle and make it smaller. How do I write code that I do not use?

Slide 24

Slide 24 text

Why tree shake? Application code is typically always used Libraries often include code you don’t use Including Angular! import from @angular/material. ES6 import all by default Tree-shaker does understand code enough you use only button. The rest is thrown away.

Slide 25

Slide 25 text

How to tree shake Rollup - ES6 bundler removes not referencing code Webpack 2 - inspired by Rollup design Uglify (deprecated) → Terser (CLI)* Build-Optimizer(Angular) - know how to annotate better to tell Uglify Closure Compiler(JS Compiler) - smallest bundle, code specific way *https://github.com/terser-js/terser

Slide 26

Slide 26 text

How to tree shake Rollup - ES6 bundler removes not referencing code Webpack 2 - inspired by Rollup design Uglify (deprecated) → Terser (CLI)* Build-Optimizer(Angular) - know how to annotate better to tell Uglify Closure Compiler(JS Compiler) - smallest bundle, code specific way *https://github.com/terser-js/terser

Slide 27

Slide 27 text

Ivy is designed for tree shaking Broke runtime up in big interpreter into smaller functions, separated instructions get compiled in your template Ex. Not use i18n, content projection or SVG no instruction in compiled template

Slide 28

Slide 28 text

Ivy can tree shake Dependency Injection and View and Content Queries Animations Pipes i18n Core framework services

Slide 29

Slide 29 text

4.0+: View Engine Compiler generated data structure and runtime, runtime traverse and interpreted them. The interpreter has to handle whatever template. It doesn’t know ahead of time you use content projection, i18n or SVG. While optimizing interpreter small and optimal, the tree-shaker could not remove part of it. Interprets generated NgFactories at runtime Must support every Angular feature Impossible to tree shake or split up

Slide 30

Slide 30 text

~4.5kB Hello World application (minified, compressed) CLI tree-shaking Google Closure Compiler ~ 2.7 kB

Slide 31

Slide 31 text

Hello World Good gauge of tree-shakeability Representative of some use cases (e.g. NgElement) My app is not hello world but you definitely pay what you use. Angular Element is not complex as an app, Ivy shakes them down to where they work.

Slide 32

Slide 32 text

Optimizability Ivy is optimizable today (Optimizable with current suite JS Tool) Optimizers are a work in progress (new tools is invented everyday) Ivy is ready for future optimizers too (Ex. Closure eventually commonly uses, Ivy will be ready.)

Slide 33

Slide 33 text

Incrementality When an Ivy application depends on @angular/material, Material is already compiled when it’s installed Template Compiler & View Engine 4.0+ used global compilation (rebuild dependency, libraries ) - typescript, ngc It’s fairly difficult to get that. To do it, ivy implemented a rule call “locality”

Slide 34

Slide 34 text

Locality Components/directives/etc. depend on each other via public API only Compiling them requires only local information Safe to ship code in NPM Can compile them without needing to know too much about those dependencies using DTS file without extra medata about code. Ivy add information to DTS files for public API like selector and purely rely on TypeScript.

Slide 35

Slide 35 text

@Input @Input('property') field: string; \ Public name Private name (Implementation Detail) Component can change the field without breaking because property name is the same.

Slide 36

Slide 36 text

@Input Ex. Binding and directly using private API, it’s still work. When component or directive changes, we have to regenerate this code to assume “field” changed. We don’t know when they publish a new patch. Angular today relies on global compilation.
function updateBindings(directive: any, value: any) { directive.field = value; } Private name

Slide 37

Slide 37 text

@Input Ivy property binding generates element property instruction taking input and new value, looks up directive or component then writing value out.
ng.elementProperty(1, "property", ng.bind(ctx.value));

Slide 38

Slide 38 text

Locality in View Engine 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) ], ...); } ViewContainerRef and TemplateRef are constructor parameters for NgIf to be injected - private API of ngIf. Angular Team updates ngIf, inject something, it might break code we generate and that’s why we generate code at the end of app bundle.

Slide 39

Slide 39 text

Locality in Ivy ViewContainerRef and TemplateRef are constructor parameters for NgIf to be injected - private API of ngIf. Angular Team updates ngIf, inject something, it might break code we generate and that’s why we generate code at the end of app bundle. NgIf.ngDirectiveDef = i0.ɵdefineDirective({ factory: function NgIf_Factory(t) { return new NgIf( i0.ɵinject(ViewContainerRef), i0.ɵinject(TemplateRef) ); }, ... }); Constructor parameters go into factory function. This code is safe to ship to NPM. ngIf has information encoded on it. Just call factory function.

Slide 40

Slide 40 text

Incrementality Ivy provides a “stable API” that allows shipping AOT compiled code to NPM ng build only builds your app No big monolithic global compilation → build libs & apps separately Not only build faster, but also simplify how libraries packaged using public API no metadata

Slide 41

Slide 41 text

Flexibility Ivy is a flexible foundation for Angular going forward Not focused on new features (for now) Never been about delivering exciting new features on the day that we ship ivy, instead, it’s about make Angular better, faster compiles, small bundles, better debuggability. However, during undertaking big effort to make our design give us a foundation for building cool features users wanted - good technical direction. Ivy Instruction sets make us very extensible - New instructions, no remove instructions - existing apps still work.

Slide 42

Slide 42 text

Ivy new features Better JIT/AOT interop (hybrid app - AOT with JIT such as $compile Angular.js, cost of shipping compiler to browser) No .ngfactory complications (still generate apps because still import, but shims, in the future, bootstrapping API simpler) Lazy loading without the Router (Now lazy-load Angular only CLI) Dynamic import & deployment

Slide 43

Slide 43 text

Potential future ideas Hand written templates (write ivy instruction sets!!!!!!!!!!!) Ecosystem on top of Ivy (empower the library from ivy low-level APIs) Higher order components (function wrap component, function adds behavior or does something else)

Slide 44

Slide 44 text

Flexibility Ivy is a flexible foundation for Angular in the future Not focused on new features (for now) Once it’s achieved, long list of ideas to investigate

Slide 45

Slide 45 text

Summary Significant refactoring Simplify Angular internal complexity, remove need of NgFactory file, simplify bootstrapping, improve lazy-loading, get rid of user stumbling block Instruction set makes templates optimizable, and make framework itself tree-shakeable. Global to incremental compilation, build faster Reduce requirement on libraries

Slide 46

Slide 46 text

Thank you Copy & Edit from: bit.ly/TheoryOfIvy Slides: http://bit.ly/2KElJuu Siwat Kaolueng @perjerz3434