What is the difference between Angular AOT and JIT compiler

前端 未结 3 1890
一生所求
一生所求 2020-12-14 03:57

I am diving into angular 4 and I am trying to understand the compilation. I\'ve read that AOT and JIT both compile TypeScript to JavaScript whether that is server side or on

3条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-14 04:38

    First of all angular is moving away from JIT compilation. I hope we will see it in angular@5.x.x

    Angular compiler takes all metadata you write by using decorators like

    @Component({
      selector: 'my-app',
      template: '

    Hello

    'm styles: [ ':host { display: block }' ] }) constructor( @Host() @Optional() private parent: Parent, @Attribute('name') name: string) {} @ViewChild('ref') ref; @ContentChildren(MyDir) children: QueryList; @HostBinding('title') title; @HostListener('click') onClick() { ... } // and so on

    and analizes it. Then it takes template and stylesheets and parses it. Compiler goes through many steps that i won't describe here. You can take a look at the following page that describes the compilation process. There is also great talk from Tobias Bosch. Finally compiler creates ngfactories to instantiate our application.

    I think main differences between AOT in JIT are

    • when and where angular runs compilation
    • how compiler collects metadata
    • what's the format of ngfactory that compiler produces

    JIT compiler

    runs on client side in our browser on every page load.

    It collects metadata by using ReflectionCapabilities API from @angular/core package. We have the following options to work with metadata in JIT mode:

    1) direct API

    for example we can declare our component like

    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 we can write in ES5. JIT compiler will read annotations and propMetadata static properties. AOT compiler won't 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 code above usually is generated by some library. Angular package also has the same format. This also won't work with aot. We have to ship metadata.json file with our library for AOT compilation.

    3) getting metadata created by invoking the decorators

    @Component({
      selector: 'my-app',
      templateUrl: `./app.component.html`
    })
    export class AppComponent {
      @HostBinding('title') test = 'Some title';
    }
    

    Typescript compiler transforms the preceding 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 Component decorator

    const TypeDecorator: TypeDecorator = function TypeDecorator(cls: Type) {
          // 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 it doesn't use Reflect api anymore. Compiler reads data directly from __annotations__ property

    if (typeOrFunc.hasOwnProperty(ANNOTATIONS)) {
      return (typeOrFunc as any)[ANNOTATIONS];
    }
    

    JIT compiler produces javascript ngfactories

    AOT compiler

    runs on server side (nodejs) at build time by using ngc.

    With AOT, there is no runtime compile step. When we run our application in browser we have already precompiled ngfactories. It gives us better performance at first and lazy load. We also don't ship @angular/compiler code in our production bundle anymore. But our bundle can grow significantly because of our ngfactories code.

    AOT compiler uses typescript api to analize typescript code. To get metadata compiler goes through StaticSymbolResolver and MetadataCollector APIs.

    So it takes app.component.ts file and creates typescript object model. So our AppComponent class will be presented like NodeObject with type 229 (ClassDeclaration)

    as we can see this object has decorators property

    and special typescript wrapper written by angular team and called tsc-wrapper does hard work to extract this metadata.

    When compiler meets d.ts file it is trying 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)];
      }
    }
    

    And finally AOT compiler uses TypeScriptEmitter to produce typescript ngfactories (angular < 4.4.0)

    See also

    • How aot works

提交回复
热议问题