私はangular 4に飛び込み、コンパイルを理解しようとしています。AOTとJITの両方が、サーバー側であろうとクライアント側であろうとTypeScriptをJavaScriptにコンパイルすることを読みました。 Webpackでビルドし、うなり声を上げてその縮小されたjavascriptを展開するときに、AOTとJITがどのように見えてくるかをコンパイルしていますか?
AOTとJITの両方が、サーバー側であろうとクライアント側であろうとTypeScriptをJavaScriptにコンパイルすることを読みました。
いいえ、それはAOTおよびJITコンパイラが行うことではありません。 TypeScriptは、TypeScriptコンパイラを使用してJavaScriptに変換されます。
コンパイルとコード生成のハードワークを行うコンパイラーが2つあります。
ビューコンパイラは、コンポーネントテンプレートと ビューファクトリを生成 をコンパイルします。テンプレート内の式とhtml要素を解析し、多くの標準コンパイラフェーズを通過します。
parse-tree (lexer) -> abstract-syntax-tree (parser) -> intermediate-code-tree -> output
プロバイダーコンパイラはモジュールプロバイダーをコンパイルし、 モジュールファクトリーを生成 します。
これらの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の主な違いは
ngfactory
の形式は何ですかすべてのページの読み込みでブラウザのクライアント側で実行されます。
_@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を作成します
ngc
を使用して、ビルド時にサーバー側(nodejs)で実行されます。
AOTでは、ランタイムコンパイル手順はありません。ブラウザでアプリケーションを実行すると、ngfactories
がプリコンパイルされています。これにより、最初の遅延ロードでパフォーマンスが向上します。また、本番バンドルには_@angular/compiler
_コードを同梱しません。ただし、ngfactories
コードのため、バンドルは大幅に成長する可能性があります。
AOTコンパイラは、 TypeScript api を使用してTypeScriptコードを分析します。メタデータコンパイラを取得するには、 StaticSymbolResolver および MetadataCollector APIを使用します。
したがって、_app.component.ts
_ファイルを受け取り、TypeScriptオブジェクトモデルを作成します。そのため、AppComponent
クラスは、_229
_(NodeObject
)型のClassDeclaration
のように表示されます
このオブジェクトにはdecorators
プロパティがあることがわかります
そして、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)
こちらもご覧ください
ブラウザがアプリバンドルをロードした後、Angularコンパイラ(vendor.bundle.js内にパッケージ化))はmain.bundle.jsからテンプレートのコンパイルを実行します。これはJust-in-Timeと呼ばれますコンパイル:この用語は、ブラウザーへのバンドルの到着時にコンパイルが行われることを意味します。
JITコンパイルの欠点は次のとおりです。
バンドルのロードとUIのレンダリングには時間差があります。この時間はJiTのコンパイルに費やされます。今回は小さなアプリでは最小限ですが、大きなアプリでは、JiTのコンパイルに数秒かかることがあるため、ユーザーはアプリを表示するまでさらに待つ必要があります。
Angularコンパイラは、アプリのサイズを増やすvendor.bundle.jsに含める必要があります。
ProdでJiTコンパイルを使用することはお勧めしません。バンドルを作成する前にテンプレートをJavaScriptにプリコンパイルしておく必要があります。これがAhead-of-Time(AoT)コンパイルの目的です。
AoTコンパイルの利点は次のとおりです。
ブラウザは、アプリがロードされるとすぐにUIをレンダリングできます。コードのコンパイルを待つ必要はありません。
Ngcコンパイラはvendor.bundle.jsに含まれていないため、アプリの結果のサイズは小さくなる可能性があります。
Webpackを使用している場合、AoTを実行するには、ngcコンパイラーを呼び出す必要があります。例えば:
"build:aot": "ngc -p tsconfig.json && webpack --config webpack.config.js"