feat(compiler): support sync runtime compile
Adds new abstraction `Compiler` with methods `compileComponentAsync` and `compileComponentSync`. This is in preparation of deprecating `ComponentResolver`. `compileComponentSync` is able to compile components synchronously given all components either have an inline template or they have been compiled before. Also changes `TestComponentBuilder.createSync` to take a `Type` and use the new `compileComponentSync` method. Also supports overriding the component metadata even if the component has already been compiled. Also fixes #7084 in a better way. BREAKING CHANGE: `TestComponentBuilder.createSync` now takes a component type and throws if not all templates are either inlined are compiled before via `createAsync`. Closes #9594
This commit is contained in:
@ -14,7 +14,7 @@ import {ListWrapper} from './facade/collection';
|
||||
import {BaseException} from './facade/exceptions';
|
||||
import {OutputEmitter} from './output/abstract_emitter';
|
||||
import * as o from './output/output_ast';
|
||||
import {StyleCompiler, StylesCompileResult} from './style_compiler';
|
||||
import {CompiledStylesheet, StyleCompiler} from './style_compiler';
|
||||
import {TemplateParser} from './template_parser';
|
||||
import {assetUrl} from './util';
|
||||
import {ComponentFactoryDependency, ViewCompileResult, ViewCompiler, ViewFactoryDependency} from './view_compiler/view_compiler';
|
||||
@ -44,29 +44,38 @@ export class OfflineCompiler {
|
||||
constructor(
|
||||
private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
|
||||
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
|
||||
private _outputEmitter: OutputEmitter, private _xhr: XHR) {}
|
||||
private _outputEmitter: OutputEmitter) {}
|
||||
|
||||
normalizeDirectiveMetadata(directive: CompileDirectiveMetadata):
|
||||
Promise<CompileDirectiveMetadata> {
|
||||
return this._directiveNormalizer.normalizeDirective(directive);
|
||||
return this._directiveNormalizer.normalizeDirective(directive).asyncResult;
|
||||
}
|
||||
|
||||
compileTemplates(components: NormalizedComponentWithViewDirectives[]): SourceModule {
|
||||
compileTemplates(components: NormalizedComponentWithViewDirectives[]): SourceModule[] {
|
||||
if (components.length === 0) {
|
||||
throw new BaseException('No components given');
|
||||
}
|
||||
var statements: o.DeclareVarStmt[] = [];
|
||||
var exportedVars: string[] = [];
|
||||
var moduleUrl = _ngfactoryModuleUrl(components[0].component.type);
|
||||
var outputSourceModules: SourceModule[] = [];
|
||||
components.forEach(componentWithDirs => {
|
||||
var compMeta = <CompileDirectiveMetadata>componentWithDirs.component;
|
||||
_assertComponent(compMeta);
|
||||
var fileSuffix = _splitLastSuffix(compMeta.type.moduleUrl)[1];
|
||||
var stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
|
||||
stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => {
|
||||
outputSourceModules.push(this._codgenStyles(compiledStyleSheet, fileSuffix));
|
||||
});
|
||||
|
||||
var compViewFactoryVar = this._compileComponent(
|
||||
compMeta, componentWithDirs.directives, componentWithDirs.pipes, statements);
|
||||
compMeta, componentWithDirs.directives, componentWithDirs.pipes,
|
||||
stylesCompileResults.componentStylesheet, fileSuffix, statements);
|
||||
exportedVars.push(compViewFactoryVar);
|
||||
|
||||
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
|
||||
var hostViewFactoryVar = this._compileComponent(hostMeta, [compMeta], [], statements);
|
||||
var hostViewFactoryVar =
|
||||
this._compileComponent(hostMeta, [compMeta], [], null, fileSuffix, statements);
|
||||
var compFactoryVar = _componentFactoryName(compMeta.type);
|
||||
statements.push(
|
||||
o.variable(compFactoryVar)
|
||||
@ -82,43 +91,32 @@ export class OfflineCompiler {
|
||||
.toDeclStmt(null, [o.StmtModifier.Final]));
|
||||
exportedVars.push(compFactoryVar);
|
||||
});
|
||||
return this._codegenSourceModule(moduleUrl, statements, exportedVars);
|
||||
}
|
||||
|
||||
loadAndCompileStylesheet(stylesheetUrl: string, shim: boolean, suffix: string):
|
||||
Promise<StyleSheetSourceWithImports> {
|
||||
return this._xhr.get(stylesheetUrl).then((cssText) => {
|
||||
var compileResult = this._styleCompiler.compileStylesheet(stylesheetUrl, cssText, shim);
|
||||
var importedUrls: string[] = [];
|
||||
compileResult.dependencies.forEach((dep) => {
|
||||
importedUrls.push(dep.moduleUrl);
|
||||
dep.valuePlaceholder.moduleUrl = _stylesModuleUrl(dep.moduleUrl, dep.isShimmed, suffix);
|
||||
});
|
||||
return new StyleSheetSourceWithImports(
|
||||
this._codgenStyles(stylesheetUrl, shim, suffix, compileResult), importedUrls);
|
||||
});
|
||||
outputSourceModules.unshift(this._codegenSourceModule(moduleUrl, statements, exportedVars));
|
||||
return outputSourceModules;
|
||||
}
|
||||
|
||||
private _compileComponent(
|
||||
compMeta: CompileDirectiveMetadata, directives: CompileDirectiveMetadata[],
|
||||
pipes: CompilePipeMetadata[], targetStatements: o.Statement[]): string {
|
||||
var styleResult = this._styleCompiler.compileComponent(compMeta);
|
||||
pipes: CompilePipeMetadata[], componentStyles: CompiledStylesheet, fileSuffix: string,
|
||||
targetStatements: o.Statement[]): string {
|
||||
var parsedTemplate = this._templateParser.parse(
|
||||
compMeta, compMeta.template.template, directives, pipes, compMeta.type.name);
|
||||
var viewResult = this._viewCompiler.compileComponent(
|
||||
compMeta, parsedTemplate, o.variable(styleResult.stylesVar), pipes);
|
||||
ListWrapper.addAll(
|
||||
targetStatements, _resolveStyleStatements(compMeta.type.moduleUrl, styleResult));
|
||||
var stylesExpr = componentStyles ? o.variable(componentStyles.stylesVar) : o.literalArr([]);
|
||||
var viewResult =
|
||||
this._viewCompiler.compileComponent(compMeta, parsedTemplate, stylesExpr, pipes);
|
||||
if (componentStyles) {
|
||||
ListWrapper.addAll(targetStatements, _resolveStyleStatements(componentStyles, fileSuffix));
|
||||
}
|
||||
ListWrapper.addAll(targetStatements, _resolveViewStatements(viewResult));
|
||||
return viewResult.viewFactoryVar;
|
||||
}
|
||||
|
||||
private _codgenStyles(
|
||||
inputUrl: string, shim: boolean, suffix: string,
|
||||
stylesCompileResult: StylesCompileResult): SourceModule {
|
||||
private _codgenStyles(stylesCompileResult: CompiledStylesheet, fileSuffix: string): SourceModule {
|
||||
_resolveStyleStatements(stylesCompileResult, fileSuffix);
|
||||
return this._codegenSourceModule(
|
||||
_stylesModuleUrl(inputUrl, shim, suffix), stylesCompileResult.statements,
|
||||
[stylesCompileResult.stylesVar]);
|
||||
_stylesModuleUrl(
|
||||
stylesCompileResult.meta.moduleUrl, stylesCompileResult.isShimmed, fileSuffix),
|
||||
stylesCompileResult.statements, [stylesCompileResult.stylesVar]);
|
||||
}
|
||||
|
||||
private _codegenSourceModule(
|
||||
@ -131,7 +129,7 @@ export class OfflineCompiler {
|
||||
function _resolveViewStatements(compileResult: ViewCompileResult): o.Statement[] {
|
||||
compileResult.dependencies.forEach((dep) => {
|
||||
if (dep instanceof ViewFactoryDependency) {
|
||||
dep.placeholder.moduleUrl = _ngfactoryModuleUrl(dep.comp.type);
|
||||
dep.placeholder.moduleUrl = _ngfactoryModuleUrl(dep.comp);
|
||||
} else if (dep instanceof ComponentFactoryDependency) {
|
||||
dep.placeholder.name = _componentFactoryName(dep.comp);
|
||||
dep.placeholder.moduleUrl = _ngfactoryModuleUrl(dep.comp);
|
||||
@ -142,17 +140,15 @@ function _resolveViewStatements(compileResult: ViewCompileResult): o.Statement[]
|
||||
|
||||
|
||||
function _resolveStyleStatements(
|
||||
containingModuleUrl: string, compileResult: StylesCompileResult): o.Statement[] {
|
||||
var containingSuffix = _splitSuffix(containingModuleUrl)[1];
|
||||
compileResult: CompiledStylesheet, fileSuffix: string): o.Statement[] {
|
||||
compileResult.dependencies.forEach((dep) => {
|
||||
dep.valuePlaceholder.moduleUrl =
|
||||
_stylesModuleUrl(dep.moduleUrl, dep.isShimmed, containingSuffix);
|
||||
dep.valuePlaceholder.moduleUrl = _stylesModuleUrl(dep.moduleUrl, dep.isShimmed, fileSuffix);
|
||||
});
|
||||
return compileResult.statements;
|
||||
}
|
||||
|
||||
function _ngfactoryModuleUrl(comp: CompileIdentifierMetadata): string {
|
||||
var urlWithSuffix = _splitSuffix(comp.moduleUrl);
|
||||
var urlWithSuffix = _splitLastSuffix(comp.moduleUrl);
|
||||
return `${urlWithSuffix[0]}.ngfactory${urlWithSuffix[1]}`;
|
||||
}
|
||||
|
||||
@ -170,7 +166,7 @@ function _assertComponent(meta: CompileDirectiveMetadata) {
|
||||
}
|
||||
}
|
||||
|
||||
function _splitSuffix(path: string): string[] {
|
||||
function _splitLastSuffix(path: string): string[] {
|
||||
let lastDot = path.lastIndexOf('.');
|
||||
if (lastDot !== -1) {
|
||||
return [path.substring(0, lastDot), path.substring(lastDot)];
|
||||
|
Reference in New Issue
Block a user