Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between Angular AOT and JIT compiler

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 the client side. If I am compiling it when I build it with Webpack and grunt and deploying that minified javascript how does AOT and JIT even come into the picture?

like image 244
CW1 Avatar asked Aug 16 '17 00:08

CW1


People also ask

What is AOT compiler in Angular?

The Angular ahead-of-time (AOT) compiler converts your Angular HTML and TypeScript code into efficient JavaScript code during the build phase before the browser downloads and runs that code. Compiling your application during the build process provides a faster rendering in the browser.

Is AOT faster than JIT?

In theory, a Just-in-Time (JIT) compiler has an advantage over Ahead-of-Time (AOT) if it has enough time and computational resources available. A JIT compiler can be faster because the machine code is being generated on the exact machine that it will also execute on.

What is the difference between AOT and ivy?

AOT compilation with Ivy is faster and should be used by default. In the angular. json workspace configuration file, set the default build options for your project to always use AOT compilation. When using application internationalization (i18n) with Ivy, translation merging also requires the use of AOT compilation.

Is Angular compiled or interpreted?

But angular is a javascript framework but is compiled.


3 Answers

I've read that AOT and JIT both compile TypeScript to JavaScript whether that is server side or on the client side.

No, that is not what AOT and JIT compilers do. TypeScript is transpiled into JavaScript using typescript compiler.

Angular compiler

There are two compilers that do the hard work of compilation and code generation:

  • view compiler
  • provider compiler

The view compiler compiles component templates and generates view factories. It parses expressions and html elements inside the template and goes through many of the standard compiler phases:

parse-tree (lexer) -> abstract-syntax-tree (parser) -> intermediate-code-tree -> output

The provider compiler compiles module providers and generates module factories.

JIT vs AOT

These two compilers are used in both JIT and AOT compilation. JIT and AOT compilations differ in how they get the metadata associated with the component or module:

// the view compiler needs this data

@Component({
   providers: ...
   template: ...
})

// the provider compiler needs this data

@NgModule({
   providers: ...
});

JIT compiler uses runtime to get the data. The decorator functions @Component and @NgModule are executed and they attach metadata to the component or module class that is later read by Angular compilers using reflective capabiliteis (Reflect library).

AOT compiler uses static code analysis provided by typescript compiler to extract metadata and doesn't rely on code evaluation. Hence it's a bit limited when compared to JIT compiler since it can't evaluate in-explicit code - for example it requires exporting a function:

// this module scoped function

function declarations() {
  return [
    SomeComponent
  ]
}

// should be exported

export function declarations() {
  return [
    SomeComponent
  ];
}
@NgModule({
  declarations: declarations(),
})
export class SomeModule {}

Again, both JIT and AOT compilers are mostly wrappers to extract metadata associated with a component or module and they both use the underlying view and provider compiler to generate factories.

If I am compiling it when I build it with Webpack and grunt and deploying that minified javascript how does AOT and JIT even come into the picture?

Angular provides webpack plugin that performs transpilation from typescript during build. This plugin can also AOT compile your project so that you don't include JIT compiler into the bundle and don't perform compilation on the client.

like image 159
Max Koretskyi Avatar answered Oct 06 '22 11:10

Max Koretskyi


First of all angular is moving away from JIT compilation. I hope we will see it in [email protected]

Angular compiler takes all metadata you write by using decorators like

@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 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 = <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 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)

enter image description here

as we can see this object has decorators property

enter image description here

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
like image 34
yurzui Avatar answered Oct 06 '22 11:10

yurzui


After the browser loads your app bundles, the Angular compiler (packaged inside vendor.bundle.js)performs the compilation of the templates from main.bundle.js. This is called Just-in-Time compilation. This term means that the compilation happens in time of the arrival of the bundles to the browser.

The drawbacks of the JIT compilation are:

  1. There is a time gap between the loading bundles and rendering the UI. This time is spent on JiT compilation. On a small app this time is minimal, but in larger apps, the JiT compilation can take a couple of seconds, so the user needs to wait longer for just seeing your app.

  2. The Angular compiler has to be included in the vendor.bundle.js, which adds to the size of your app.

Using the JiT compilation in the prod is discouraged, and we want the templates to be pre-compiled into JavaScript before the bundles are created. This is what Ahead-of-Time (AoT) compilation is about.

The advantages of the AoT compilation are:

  1. The browser can render the UI as soon as you app is loaded. There is no need to wait for code compilation.

  2. The ngc compiler is not included in the vendor.bundle.js and the resulting size of your app might be smaller.

If you're using Webpack, to do AoT you need to invoke the ngc compiler. For example:

"build:aot": "ngc -p tsconfig.json && webpack --config webpack.config.js"
like image 21
Yakov Fain Avatar answered Oct 06 '22 11:10

Yakov Fain