First of all, angular moves away from compiling JIT. I hope we see this at angular@5.xx
The angular compiler accepts all metadata that you write using decorators such as
@Component({ selector: 'my-app', template: '<h1>Hello</h1>'m styles: [ ':host { display: block }' ] }) constructor( @Host() @Optional() private parent: Parent, @Attribute('name') name: string) {} @ViewChild('ref') ref; @ContentChildren(MyDir) children: QueryList<MyDir>; @HostBinding('title') title; @HostListener('click') onClick() { ... } // and so on
and analyzes it. He then takes a template and style sheet and parses it. The compiler goes through many steps, which I will not describe here. You can see the next page that describes the compilation process. There is also a great chat from Tobias Bosch. Finally, the compiler creates ngfactories to instantiate our application.
I think the main differences between AOT in JIT are
- when and where angular starts compilation
- how the collector collects metadata
- what format
ngfactory compiler give ngfactory
Jit compiler
It works on the client side in our browser every time the page loads .
It collects metadata using the ReflectionCapabilities API from the @angular/core package. We have the following options for working with metadata in JIT mode:
1) direct API
for example, we can declare our component as
export class AppComponent { static annotations = [ new Component({ selector: 'my-app', templateUrl: `./app.component.html`, styles: [ ':host { display: block }' ] }) ]; test: string; static propMetadata = { test: [new HostBinding('title')] }; ngOnInit() { this.test = 'Some title' } }
Similar code can be written to ES5. The JIT compiler will read the static properties annotations and propMetadata . AOT compiler will not work with it.
2) tsickle API
export class AppComponent { static decorators = [{ type: Component, args: [{ selector: 'my-app', templateUrl: `./app.component.html`, styles: [ ':host { display: block }' ] },] }]; test: string; static propDecorators = { 'test': [{ type: HostBinding, args: ['title'] }] }; ngOnInit() { this.test = 'Some title' } }
The above code is usually generated by some library. The angular package also has the same format. This will also not work with aot. We must send the metadata.json file with our library to compile AOT.
3) getting metadata created by calling decorators
@Component({ selector: 'my-app', templateUrl: `./app.component.html` }) export class AppComponent { @HostBinding('title') test = 'Some title'; }
Typescript compiler converts previous code to
var AppComponent = (function () { function AppComponent() { this.test = 'Some title'; } return AppComponent; }()); __decorate([ HostBinding('title') ], AppComponent.prototype, "test", void 0); AppComponent = __decorate([ Component({ selector: 'my-app', templateUrl: "./app.component.html" }) ], AppComponent);
this code is executed in JIT mode, so angular calls the component decoder
const TypeDecorator: TypeDecorator = <TypeDecorator>function TypeDecorator(cls: Type<any>) { // Use of Object.defineProperty is important since it creates non-enumerable property which // prevents the property is copied during subclassing. const annotations = cls.hasOwnProperty(ANNOTATIONS) ? (cls as any)[ANNOTATIONS] : Object.defineProperty(cls, ANNOTATIONS, {value: []})[ANNOTATIONS]; annotations.push(annotationInstance); return cls; };
Today no longer uses the Reflect api . The compiler reads data directly from the __annotations__ property
if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) { return (typeOrFunc as any)[ANNOTATIONS]; }
JIT compiler creates javascript ngfactories
AOT compiler
runs on server side (nodejs) during build using ngc .
Using AOT does not execute the compilation stage at run time. When we launch our application in a browser, we already precompiled ngfactories . This gives us better performance at the beginning and lazy workload. Nor do we ship the @angular/compiler code in our production kit. But our package can grow significantly due to our ngfactories code.
The AOT compiler uses the Typescript api to parse typescript code. To obtain metadata, the compiler navigates through StaticSymbolResolver and the MetadataCollector APIs .
Therefore, it accepts the app.component.ts file and creates the typescript object model. Therefore, our AppComponent class will be represented as a NodeObject with type 229 ( ClassDeclaration )

as we can see, this object has the decorators property

and a special typescript wrapper written by the angular command and calling tsc-wrapper does the hard work to extract this metadata.
When the compiler encounters a d.ts file , it tries to get metadata from metadata.json :
if (DTS.test(filePath)) { var metadataPath = filePath.replace(DTS, '.metadata.json'); if (this.context.fileExists(metadataPath)) { return this.readMetadata(metadataPath, filePath); } else { // If there is a .d.ts file but no metadata file we need to produce a // v3 metadata from the .d.ts file as v3 includes the exports we need // to resolve symbols. return [this.upgradeVersion1Metadata({ '__symbolic': 'module', 'version': 1, 'metadata': {} }, filePath)]; } }
Finally, the AOT compiler uses TypeScriptEmitter to produce typescript ngfactories (angular <4.4. 0)
see also