web-dev-qa-db-ja.com

Angular AOTとJITコンパイラの違いは何ですか

私はangular 4に飛び込み、コンパイルを理解しようとしています。AOTとJITの両方が、サーバー側であろうとクライアント側であろうとTypeScriptをJavaScriptにコンパイルすることを読みました。 Webpackでビルドし、うなり声を上げてその縮小されたjavascriptを展開するときに、AOTとJITがどのように見えてくるかをコンパイルしていますか?

13
CW1

AOTとJITの両方が、サーバー側であろうとクライアント側であろうとTypeScriptをJavaScriptにコンパイルすることを読みました。

いいえ、それはAOTおよびJITコンパイラが行うことではありません。 TypeScriptは、TypeScriptコンパイラを使用してJavaScriptに変換されます。

角度コンパイラ

コンパイルとコード生成のハードワークを行うコンパイラーが2つあります。

ビューコンパイラは、コンポーネントテンプレートと ビューファクトリを生成 をコンパイルします。テンプレート内の式とhtml要素を解析し、多くの標準コンパイラフェーズを通過します。

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

プロバイダーコンパイラはモジュールプロバイダーをコンパイルし、 モジュールファクトリーを生成 します。

JIT vs AOT

これらの2つのコンパイラは、JITコンパイルとAOTコンパイルの両方で使用されます。 JITとAOTのコンパイルは、コンポーネントまたはモジュールに関連付けられたメタデータを取得する方法が異なります。

// the view compiler needs this data

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

// the provider compiler needs this data

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

JITコンパイラーは、ランタイムを使用してデータを取得します。デコレータ関数@Componentおよび@NgModuleが実行され、 メタデータが付加されます コンポーネントまたはモジュールクラスにAngular反射機能(Reflectライブラリ)を使用するコンパイラーによって後で読み取られます。

AOTコンパイラは、TypeScriptコンパイラが提供する静的コード分析を使用してメタデータを抽出し、コード評価に依存しません。したがって、明示的なコードを評価できないため、JITコンパイラと比較した場合、少し制限されています。たとえば、関数をエクスポートする必要があります。

// this module scoped function

function declarations() {
  return [
    SomeComponent
  ]
}

// should be exported

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

繰り返しますが、JITコンパイラとAOTコンパイラはどちらも、コンポーネントまたはモジュールに関連付けられたメタデータを抽出するためのラッパーであり、基になるビューとプロバイダーコンパイラを使用してファクトリを生成します。

Webpackでビルドし、うなり声を上げてその縮小されたjavascriptを展開するときにコンパイルする場合、AOTとJITはどのように見えますか?

Angularは、ビルド中にTypeScriptからの翻訳を実行する webpackプラグイン を提供します。このプラグインはプロジェクトをAOTコンパイルすることもできるため、JITコンパイラをバンドルに含めず、クライアントでコンパイルを実行しません。

まず第一にangularはJITコンパイルから遠ざかります。_[email protected]_に表示されることを望みます。

Angularコンパイラは、次のようなデコレータを使用して、作成したすべてのメタデータを取得します

_@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
_

そしてそれを分析します。次に、テンプレートとスタイルシートを取得して解析します。コンパイラは、ここでは説明しませんが、多くの手順を実行します。 次のページ でコンパイルプロセスについて説明しています。 Tobias Boschからの great talk もあります。最後に、コンパイラーはngfactoriesを作成してアプリケーションをインスタンス化します。

JITのAOTの主な違いは

  • いつ、どこでangularはコンパイルを実行します
  • コンパイラがメタデータを収集する方法
  • コンパイラが生成するngfactoryの形式は何ですか

JITコンパイラー

すべてのページの読み込みでブラウザのクライアント側で実行されます

_@angular/core_パッケージの ReflectionCapabilities API を使用してメタデータを収集します。 JITモードでメタデータを操作するには、次のオプションがあります。

1)ダイレクトAPI

たとえば、次のようにコンポーネントを宣言できます

_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'
  }
}
_

ES5で記述できる同様のコード。 JITコンパイラは、annotationsおよびpropMetadata静的プロパティを読み取ります。 AOTコンパイラーは動作しません。

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'
  }
}
_

上記のコードは通常、いくつかのライブラリによって生成されます。 Angularパッケージも同じ形式です。これもaotでは動作しません。AOTコンパイル用にライブラリに_metadata.json_ファイルを同梱する必要があります。

3)デコレータを呼び出してメタデータを作成する

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

TypeScriptコンパイラは、前述のコードを

_ 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);
_

このコードはJITモードで実行されるため、angular ]コンポーネントデコレータ を呼び出します

_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;
};
_

今日では はReflect APIを使用しなくなりました 。コンパイラは___annotations___プロパティからデータを直接読み取ります

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

JITコンパイラーはJavaScript ngfactoriesを作成します

AOTコンパイラ

ngcを使用して、ビルド時にサーバー側(nodejs)で実行されます。

AOTでは、ランタイムコンパイル手順はありません。ブラウザでアプリケーションを実行すると、ngfactoriesがプリコンパイルされています。これにより、最初の遅延ロードでパフォーマンスが向上します。また、本番バンドルには_@angular/compiler_コードを同梱しません。ただし、ngfactoriesコードのため、バンドルは大幅に成長する可能性があります。

AOTコンパイラは、 TypeScript api を使用してTypeScriptコードを分析します。メタデータコンパイラを取得するには、 StaticSymbolResolver および MetadataCollector APIを使用します。

したがって、_app.component.ts_ファイルを受け取り、TypeScriptオブジェクトモデルを作成します。そのため、AppComponentクラスは、_229_(NodeObject)型のClassDeclarationのように表示されます

enter image description here

このオブジェクトにはdecoratorsプロパティがあることがわかります

enter image description here

そして、angular teamによって書かれ、_tsc-wrapper_ と呼ばれる特別なTypeScriptラッパーは、このメタデータを抽出するためにハードワーク を行います。

コンパイラが が_d.ts_ file に一致すると、_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)];
  }
}
_

そして最後に、AOTコンパイラは TypeScriptEmitter を使用してTypeScript ngfactoriesを生成します(角度<4.4.0)

こちらもご覧ください

18
yurzui

ブラウザがアプリバンドルをロードした後、Angularコンパイラ(vendor.bundle.js内にパッケージ化))はmain.bundle.jsからテンプレートのコンパイルを実行します。これはJust-in-Timeと呼ばれますコンパイル:この用語は、ブラウザーへのバンドルの到着時にコンパイルが行われることを意味します。

JITコンパイルの欠点は次のとおりです。

  1. バンドルのロードとUIのレンダリングには時間差があります。この時間はJiTのコンパイルに費やされます。今回は小さなアプリでは最小限ですが、大きなアプリでは、JiTのコンパイルに数秒かかることがあるため、ユーザーはアプリを表示するまでさらに待つ必要があります。

  2. Angularコンパイラは、アプリのサイズを増やすvendor.bundle.jsに含める必要があります。

ProdでJiTコンパイルを使用することはお勧めしません。バンドルを作成する前にテンプレートをJavaScriptにプリコンパイルしておく必要があります。これがAhead-of-Time(AoT)コンパイルの目的です。

AoTコンパイルの利点は次のとおりです。

  1. ブラウザは、アプリがロードされるとすぐにUIをレンダリングできます。コードのコンパイルを待つ必要はありません。

  2. Ngcコンパイラはvendor.bundle.jsに含まれていないため、アプリの結果のサイズは小さくなる可能性があります。

Webpackを使用している場合、AoTを実行するには、ngcコンパイラーを呼び出す必要があります。例えば:

"build:aot": "ngc -p tsconfig.json && webpack --config webpack.config.js"
4
Yakov Fain