refactor(compiler): allow sync AOT compilation (#16832).

AOT compilation can be executed synchronously now,
if the `ReosurceLoader` returns a string directly
(and no `Promise`).
This commit is contained in:
Tobias Bosch
2017-05-17 15:39:08 -07:00
committed by Chuck Jazdzewski
parent 255d7226d1
commit 5af143e8e4
15 changed files with 577 additions and 643 deletions

View File

@ -18,7 +18,7 @@ import {ResourceLoader} from './resource_loader';
import {extractStyleUrls, isStyleUrlResolvable} from './style_url_resolver';
import {PreparsedElementType, preparseElement} from './template_parser/template_preparser';
import {UrlResolver} from './url_resolver';
import {SyncAsyncResult, isDefined, syntaxError} from './util';
import {SyncAsync, isDefined, syntaxError} from './util';
export interface PrenormalizedTemplateMetadata {
ngModuleType: any;
@ -35,7 +35,7 @@ export interface PrenormalizedTemplateMetadata {
@CompilerInjectable()
export class DirectiveNormalizer {
private _resourceLoaderCache = new Map<string, Promise<string>>();
private _resourceLoaderCache = new Map<string, SyncAsync<string>>();
constructor(
private _resourceLoader: ResourceLoader, private _urlResolver: UrlResolver,
@ -53,19 +53,17 @@ export class DirectiveNormalizer {
(stylesheet) => { this._resourceLoaderCache.delete(stylesheet.moduleUrl !); });
}
private _fetch(url: string): Promise<string> {
private _fetch(url: string): SyncAsync<string> {
let result = this._resourceLoaderCache.get(url);
if (!result) {
result = this._resourceLoader.get(url) !;
result = this._resourceLoader.get(url);
this._resourceLoaderCache.set(url, result);
}
return result;
}
normalizeTemplate(prenormData: PrenormalizedTemplateMetadata):
SyncAsyncResult<CompileTemplateMetadata> {
let normalizedTemplateSync: CompileTemplateMetadata = null !;
let normalizedTemplateAsync: Promise<CompileTemplateMetadata> = undefined !;
SyncAsync<CompileTemplateMetadata> {
if (isDefined(prenormData.template)) {
if (isDefined(prenormData.templateUrl)) {
throw syntaxError(
@ -75,39 +73,33 @@ export class DirectiveNormalizer {
throw syntaxError(
`The template specified for component ${stringify(prenormData.componentType)} is not a string`);
}
normalizedTemplateSync = this.normalizeTemplateSync(prenormData);
normalizedTemplateAsync = Promise.resolve(normalizedTemplateSync !);
} else if (isDefined(prenormData.templateUrl)) {
if (typeof prenormData.templateUrl !== 'string') {
throw syntaxError(
`The templateUrl specified for component ${stringify(prenormData.componentType)} is not a string`);
}
normalizedTemplateAsync = this.normalizeTemplateAsync(prenormData);
} else {
throw syntaxError(
`No template specified for component ${stringify(prenormData.componentType)}`);
}
return SyncAsync.then(
this.normalizeTemplateOnly(prenormData),
(result: CompileTemplateMetadata) => this.normalizeExternalStylesheets(result));
}
if (normalizedTemplateSync && normalizedTemplateSync.styleUrls.length === 0) {
// sync case
return new SyncAsyncResult(normalizedTemplateSync);
normalizeTemplateOnly(prenomData: PrenormalizedTemplateMetadata):
SyncAsync<CompileTemplateMetadata> {
let template: SyncAsync<string>;
let templateUrl: string;
if (prenomData.template != null) {
template = prenomData.template;
templateUrl = prenomData.moduleUrl;
} else {
// async case
return new SyncAsyncResult(
null, normalizedTemplateAsync.then(
(normalizedTemplate) => this.normalizeExternalStylesheets(normalizedTemplate)));
templateUrl = this._urlResolver.resolve(prenomData.moduleUrl, prenomData.templateUrl !);
template = this._fetch(templateUrl);
}
}
normalizeTemplateSync(prenomData: PrenormalizedTemplateMetadata): CompileTemplateMetadata {
return this.normalizeLoadedTemplate(prenomData, prenomData.template !, prenomData.moduleUrl);
}
normalizeTemplateAsync(prenomData: PrenormalizedTemplateMetadata):
Promise<CompileTemplateMetadata> {
const templateUrl = this._urlResolver.resolve(prenomData.moduleUrl, prenomData.templateUrl !);
return this._fetch(templateUrl)
.then((value) => this.normalizeLoadedTemplate(prenomData, value, templateUrl));
return SyncAsync.then(
template, (template) => this.normalizeLoadedTemplate(prenomData, template, templateUrl));
}
normalizeLoadedTemplate(
@ -162,37 +154,42 @@ export class DirectiveNormalizer {
}
normalizeExternalStylesheets(templateMeta: CompileTemplateMetadata):
Promise<CompileTemplateMetadata> {
return this._loadMissingExternalStylesheets(templateMeta.styleUrls)
.then((externalStylesheets) => new CompileTemplateMetadata({
encapsulation: templateMeta.encapsulation,
template: templateMeta.template,
templateUrl: templateMeta.templateUrl,
styles: templateMeta.styles,
styleUrls: templateMeta.styleUrls,
externalStylesheets: externalStylesheets,
ngContentSelectors: templateMeta.ngContentSelectors,
animations: templateMeta.animations,
interpolation: templateMeta.interpolation,
isInline: templateMeta.isInline,
}));
SyncAsync<CompileTemplateMetadata> {
return SyncAsync.then(
this._loadMissingExternalStylesheets(templateMeta.styleUrls),
(externalStylesheets) => new CompileTemplateMetadata({
encapsulation: templateMeta.encapsulation,
template: templateMeta.template,
templateUrl: templateMeta.templateUrl,
styles: templateMeta.styles,
styleUrls: templateMeta.styleUrls,
externalStylesheets: externalStylesheets,
ngContentSelectors: templateMeta.ngContentSelectors,
animations: templateMeta.animations,
interpolation: templateMeta.interpolation,
isInline: templateMeta.isInline,
}));
}
private _loadMissingExternalStylesheets(
styleUrls: string[],
loadedStylesheets:
Map<string, CompileStylesheetMetadata> = new Map<string, CompileStylesheetMetadata>()):
Promise<CompileStylesheetMetadata[]> {
return Promise
.all(styleUrls.filter((styleUrl) => !loadedStylesheets.has(styleUrl))
.map(styleUrl => this._fetch(styleUrl).then((loadedStyle) => {
const stylesheet = this.normalizeStylesheet(
new CompileStylesheetMetadata({styles: [loadedStyle], moduleUrl: styleUrl}));
loadedStylesheets.set(styleUrl, stylesheet);
return this._loadMissingExternalStylesheets(
stylesheet.styleUrls, loadedStylesheets);
})))
.then((_) => Array.from(loadedStylesheets.values()));
SyncAsync<CompileStylesheetMetadata[]> {
return SyncAsync.then(
SyncAsync.all(styleUrls.filter((styleUrl) => !loadedStylesheets.has(styleUrl))
.map(
styleUrl => SyncAsync.then(
this._fetch(styleUrl),
(loadedStyle) => {
const stylesheet =
this.normalizeStylesheet(new CompileStylesheetMetadata(
{styles: [loadedStyle], moduleUrl: styleUrl}));
loadedStylesheets.set(styleUrl, stylesheet);
return this._loadMissingExternalStylesheets(
stylesheet.styleUrls, loadedStylesheets);
}))),
(_) => Array.from(loadedStylesheets.values()));
}
normalizeStylesheet(stylesheet: CompileStylesheetMetadata): CompileStylesheetMetadata {