Aha Moments from ngconf 2016 Part 1: Angular 2.0 Compile Cycle

This is sealed that ngconf is truly the best conference ever, at least for me and I’m sure for a lot of coders like me. It actually defines the meaning of conference.

So, a lot of information gulp happened in those three days and after the third day, I was left with this one insanely huge list of “things to do after conference”. But in that list, I definitely had some Aha moments and I decided to share those here. The first in that has to be the “Angular 2.0 new Compile Cycle”, presented by Misko, father of Angular & Rob.

Lets look at the way Compile works in Angular 1

Angular 1.0 compiler is Polymorphic

The way Angular 1.0 compile works is browser fetches your template as an xhr, passes it to browser parser which basically means that it takes hidden div, does inner html, etc. on the template. Then browser parses it to the DOM so its in the DOM browser which eventually means that you have to figure out your entire tree node structure in the browser. Top of that, operations like ng-repeat does DOM cloning because of this process.

Source: https://docs.google.com/presentation/d/1pqn5uhqg1km1AXR15qugtAYV-bnMtDl_HC1HnK9b1xQ/mobilepresent?slide=id.g41a019a213999548_41

Because this compile pipeline is in browser/DOM and everything happens in browser, you can’t run it on web-workers or server and everything is unavoidably dependent on browser. E.g. Browser parser is case-insensitive which explains why dashes were used instead of uppercase and lowercase. Browser doesn’t give you line number in case of error. I remember every time I had a provider injection error, I was like this:

source: https://www.pinterest.com

Now lets look at the way it works in Angular 2.0

Compiling is Angular 2 is Monomorphic

Angular 2.0 takes the template file and run it’s own parser on it. The parser is written in javascript which is case-sensitive. Another thing to be noticed about it is that, in case of error, line numbers can be given by the parser. The parser is built in Google’s internal data structure called AST tree. Now, all of this is impure javascript hence it can run on web-worker and server. So, the process is interpret AST on the fly, generate javascript code out of it and evalid on the fly, which eventually is what exactly happens in the dynamic mode, the current mode of build. The code generated is monomorphic. AST generates typescript for you but Typescript cant be evaluated in a browser. But, in offline mode, when you generate Typescript and run it in typescript chain, because everything is typed, it can give you Compile time error checking which is a huge plus. As all the call sites always end up in the same location and browser VM can inline the function call sites, it results in a huge speed boost. This is actually the secret why the compilation is so fast and Elements rendering is super fast.

Inlining

With ES6 and Angular 2, when you start making use of Import/Export modules, proven best practice followed by rest of the industry and allows you to take your application to a bigger platform. But as your application grows, it also becomes an overhead. Renaming can be an overhead with all the hash-mapping. Smaller your App is broken, more is the overheard of imports. Inlining inlines everything in a single file with individual symbols kept next to each other, produces a new file by concatenating original file but with all imports statements removed, IIF blocks removed.

Tree-shake

Tree shake is a brilliant step in the compile process. Because of the static entry point, Tree-shaker starts a tool called Bootstrap static which refers to the generated component. Generated Component refers to actual Component which might refer to some directives in turn. The beauty of this is it only keeps the symbols that are referenced. Because of Bootstrap static, it does not reference ng-compile and that falls out. Similarly if you don’t use ng-if, it wont be added in the compiled version. So, inclusion of only what is actually needed in the application and that’s how the size is shrunk.

Minification

Minification is the regular minify process that we have been doing. The difference is that now the smaller files of 116KB gets even smaller to 49KB now. It gives us three major performance boosters here:

Reduced Size

Reduced number of Requests

Reduced Latency

Reason for latency reduced to this is now there’s a very little code, browser doesn’t have to parse a lot of load but only what is to be executed. There’s no template compiler, no template parsing, no directive lookup, execute and VM can immediately start inlining the code

Here are some details around build steps and commands to run things in different modes.

The way build process happens today is by using commonjs build and using the bundled code. This is dynamic mode where the compiler is shipped, the templates are build in the browser and everything is happening on the fly. you do npm run build:dynamic. In short, in dynamic mode, angular is built in commonjs, loading & translation happen in browser and the eventual payload size that you get is 116kb.

With the new offline-static Template compiler explained above which was also demoed for the first time in ng-conf 2016, the build process has some changes:

npm run build:static
Import a bunch of things like coreBootstrap function, ReflectiveInjector but the key is AppNgFactory. AppNGFactory is the Compiled version of your app component.
running ngc : ngc command for the new compiler
running rollup : rollup, new to javascript; allows tree-shaking

and last, when running tsc, it takes all ES6 code and convert it to ES5 so that it’s executable in the browser and the eventual file what you get is 49.4Kb file.

So, this was all I could grab about the new Compiler. More interesting stuff coming soon in this series.

References: