refactor(core): change module semantics
This contains major changes to the compiler, bootstrap of the platforms and test environment initialization. Main part of #10043 Closes #10164 BREAKING CHANGE: - Semantics and name of `@AppModule` (now `@NgModule`) changed quite a bit. This is actually not breaking as `@AppModules` were not part of rc.4. We will have detailed docs on `@NgModule` separately. - `coreLoadAndBootstrap` and `coreBootstrap` can't be used any more (without migration support). Use `bootstrapModule` / `bootstrapModuleFactory` instead. - All Components listed in routes have to be part of the `declarations` of an NgModule. Either directly on the bootstrap module / lazy loaded module, or in an NgModule imported by them.
This commit is contained in:
@ -6,13 +6,13 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AppModuleCompiler} from './app_module_compiler';
|
||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompilePipeMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
|
||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
|
||||
import {DirectiveNormalizer} from './directive_normalizer';
|
||||
import {ListWrapper} from './facade/collection';
|
||||
import {BaseException} from './facade/exceptions';
|
||||
import {Identifiers} from './identifiers';
|
||||
import {CompileMetadataResolver} from './metadata_resolver';
|
||||
import {NgModuleCompiler} from './ng_module_compiler';
|
||||
import {OutputEmitter} from './output/abstract_emitter';
|
||||
import * as o from './output/output_ast';
|
||||
import {CompiledStylesheet, StyleCompiler} from './style_compiler';
|
||||
@ -23,61 +23,29 @@ export class SourceModule {
|
||||
constructor(public moduleUrl: string, public source: string) {}
|
||||
}
|
||||
|
||||
export class AppModulesSummary {
|
||||
private _compAppModule = new Map<string, StaticSymbol>();
|
||||
private _hashKey(type: StaticSymbol) { return `${type.filePath}#${type.name}`; }
|
||||
|
||||
hasComponent(component: StaticSymbol): boolean {
|
||||
return this._compAppModule.has(this._hashKey(component));
|
||||
}
|
||||
|
||||
addComponent(module: StaticSymbol, component: StaticSymbol) {
|
||||
this._compAppModule.set(this._hashKey(component), module);
|
||||
}
|
||||
|
||||
getModule(comp: StaticSymbol): StaticSymbol {
|
||||
return this._compAppModule.get(this._hashKey(comp));
|
||||
}
|
||||
export class NgModulesSummary {
|
||||
constructor(public ngModuleByComponent: Map<StaticSymbol, CompileNgModuleMetadata>) {}
|
||||
}
|
||||
|
||||
export class OfflineCompiler {
|
||||
constructor(
|
||||
private _metadataResolver: CompileMetadataResolver,
|
||||
private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
|
||||
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
|
||||
private _appModuleCompiler: AppModuleCompiler, private _outputEmitter: OutputEmitter) {}
|
||||
private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter) {}
|
||||
|
||||
analyzeModules(appModules: StaticSymbol[]): AppModulesSummary {
|
||||
let result = new AppModulesSummary();
|
||||
appModules.forEach((appModule) => {
|
||||
let appModuleMeta = this._metadataResolver.getAppModuleMetadata(appModule);
|
||||
appModuleMeta.precompile.forEach(
|
||||
(precompileComp) =>
|
||||
this._getTransitiveComponents(appModule, <any>precompileComp.runtime, result));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
analyzeModules(ngModules: StaticSymbol[]): NgModulesSummary {
|
||||
const ngModuleByComponent = new Map<StaticSymbol, CompileNgModuleMetadata>();
|
||||
|
||||
private _getTransitiveComponents(
|
||||
appModule: StaticSymbol, component: StaticSymbol,
|
||||
target: AppModulesSummary = new AppModulesSummary()): AppModulesSummary {
|
||||
var compMeta = this._metadataResolver.getDirectiveMetadata(<any>component);
|
||||
// TODO(tbosch): preserve all modules per component, not just one.
|
||||
// Then run the template parser with the union and the intersection of the modules (regarding
|
||||
// directives/pipes)
|
||||
// and report an error if some directives/pipes are only matched with the union but not with the
|
||||
// intersection!
|
||||
// -> this means that a component is used in the wrong way!
|
||||
if (!compMeta.isComponent || target.hasComponent(component)) {
|
||||
return target;
|
||||
}
|
||||
target.addComponent(appModule, component);
|
||||
this._metadataResolver.getViewDirectivesMetadata(<any>component).forEach((dirMeta) => {
|
||||
this._getTransitiveComponents(appModule, <any>dirMeta.type.runtime);
|
||||
ngModules.forEach((ngModule) => {
|
||||
const ngModuleMeta = this._metadataResolver.getNgModuleMetadata(<any>ngModule);
|
||||
ngModuleMeta.declaredDirectives.forEach((dirMeta) => {
|
||||
if (dirMeta.isComponent) {
|
||||
ngModuleByComponent.set(dirMeta.type.runtime, ngModuleMeta);
|
||||
}
|
||||
});
|
||||
});
|
||||
compMeta.precompile.forEach((precompileComp) => {
|
||||
this._getTransitiveComponents(appModule, <any>precompileComp.type.runtime);
|
||||
});
|
||||
return target;
|
||||
return new NgModulesSummary(ngModuleByComponent);
|
||||
}
|
||||
|
||||
clearCache() {
|
||||
@ -86,55 +54,45 @@ export class OfflineCompiler {
|
||||
}
|
||||
|
||||
compile(
|
||||
moduleUrl: string, appModulesSummary: AppModulesSummary, components: StaticSymbol[],
|
||||
appModules: StaticSymbol[]): Promise<SourceModule[]> {
|
||||
moduleUrl: string, ngModulesSummary: NgModulesSummary, components: StaticSymbol[],
|
||||
ngModules: StaticSymbol[]): Promise<SourceModule[]> {
|
||||
let fileSuffix = _splitLastSuffix(moduleUrl)[1];
|
||||
let statements: o.Statement[] = [];
|
||||
let exportedVars: string[] = [];
|
||||
let outputSourceModules: SourceModule[] = [];
|
||||
|
||||
// compile app modules
|
||||
// compile all ng modules
|
||||
exportedVars.push(
|
||||
...appModules.map((appModule) => this._compileAppModule(appModule, statements)));
|
||||
...ngModules.map((ngModuleType) => this._compileModule(ngModuleType, statements)));
|
||||
|
||||
// compile components
|
||||
return Promise
|
||||
.all(components.map((compType) => {
|
||||
let appModule = appModulesSummary.getModule(compType);
|
||||
let appModuleDirectives: CompileDirectiveMetadata[] = [];
|
||||
let appModulePipes: CompilePipeMetadata[] = [];
|
||||
if (appModule) {
|
||||
let appModuleMeta = this._metadataResolver.getAppModuleMetadata(appModule);
|
||||
appModuleDirectives.push(...appModuleMeta.directives.map(
|
||||
type => this._metadataResolver.getDirectiveMetadata(type.runtime)));
|
||||
appModulePipes.push(...appModuleMeta.pipes.map(
|
||||
type => this._metadataResolver.getPipeMetadata(type.runtime)));
|
||||
const compMeta = this._metadataResolver.getDirectiveMetadata(<any>compType);
|
||||
let ngModule = ngModulesSummary.ngModuleByComponent.get(compType);
|
||||
if (!ngModule) {
|
||||
throw new BaseException(
|
||||
`Cannot determine the module for component ${compMeta.type.name}!`);
|
||||
}
|
||||
return Promise
|
||||
.all([
|
||||
this._metadataResolver.getDirectiveMetadata(<any>compType), ...appModuleDirectives,
|
||||
...this._metadataResolver.getViewDirectivesMetadata(<any>compType)
|
||||
].map(dirMeta => this._directiveNormalizer.normalizeDirective(dirMeta).asyncResult))
|
||||
.all([compMeta, ...ngModule.transitiveModule.directives].map(
|
||||
dirMeta => this._directiveNormalizer.normalizeDirective(dirMeta).asyncResult))
|
||||
.then((normalizedCompWithDirectives) => {
|
||||
let compMeta = normalizedCompWithDirectives[0];
|
||||
let dirMetas = normalizedCompWithDirectives.slice(1);
|
||||
const compMeta = normalizedCompWithDirectives[0];
|
||||
const dirMetas = normalizedCompWithDirectives.slice(1);
|
||||
_assertComponent(compMeta);
|
||||
|
||||
// compile styles
|
||||
let stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
|
||||
const stylesCompileResults = this._styleCompiler.compileComponent(compMeta);
|
||||
stylesCompileResults.externalStylesheets.forEach((compiledStyleSheet) => {
|
||||
outputSourceModules.push(this._codgenStyles(compiledStyleSheet, fileSuffix));
|
||||
});
|
||||
|
||||
// compile components
|
||||
exportedVars.push(this._compileComponentFactory(compMeta, fileSuffix, statements));
|
||||
let pipeMetas = [
|
||||
...appModulePipes,
|
||||
...this._metadataResolver.getViewPipesMetadata(compMeta.type.runtime)
|
||||
];
|
||||
exportedVars.push(this._compileComponent(
|
||||
compMeta, dirMetas, pipeMetas, stylesCompileResults.componentStylesheet,
|
||||
fileSuffix, statements));
|
||||
compMeta, dirMetas, ngModule.transitiveModule.pipes,
|
||||
stylesCompileResults.componentStylesheet, fileSuffix, statements));
|
||||
});
|
||||
}))
|
||||
.then(() => {
|
||||
@ -146,21 +104,21 @@ export class OfflineCompiler {
|
||||
});
|
||||
}
|
||||
|
||||
private _compileAppModule(appModuleType: StaticSymbol, targetStatements: o.Statement[]): string {
|
||||
let appModuleMeta = this._metadataResolver.getAppModuleMetadata(appModuleType);
|
||||
let appCompileResult = this._appModuleCompiler.compile(appModuleMeta);
|
||||
private _compileModule(ngModuleType: StaticSymbol, targetStatements: o.Statement[]): string {
|
||||
const ngModule = this._metadataResolver.getNgModuleMetadata(<any>ngModuleType);
|
||||
let appCompileResult = this._ngModuleCompiler.compile(ngModule, []);
|
||||
appCompileResult.dependencies.forEach((dep) => {
|
||||
dep.placeholder.name = _componentFactoryName(dep.comp);
|
||||
dep.placeholder.moduleUrl = _ngfactoryModuleUrl(dep.comp.moduleUrl);
|
||||
});
|
||||
targetStatements.push(...appCompileResult.statements);
|
||||
return appCompileResult.appModuleFactoryVar;
|
||||
return appCompileResult.ngModuleFactoryVar;
|
||||
}
|
||||
|
||||
private _compileComponentFactory(
|
||||
compMeta: CompileDirectiveMetadata, fileSuffix: string,
|
||||
targetStatements: o.Statement[]): string {
|
||||
var hostMeta = createHostComponentMeta(compMeta.type, compMeta.selector);
|
||||
var hostMeta = createHostComponentMeta(compMeta);
|
||||
var hostViewFactoryVar =
|
||||
this._compileComponent(hostMeta, [compMeta], [], null, fileSuffix, targetStatements);
|
||||
var compFactoryVar = _componentFactoryName(compMeta.type);
|
||||
|
Reference in New Issue
Block a user