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:
Tobias Bosch
2016-07-18 03:50:31 -07:00
parent ca16fc29a6
commit 46b212706b
129 changed files with 3580 additions and 3366 deletions

View File

@ -6,14 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Injector} from '../di';
import {Injector, OpaqueToken} from '../di';
import {BaseException} from '../facade/exceptions';
import {ConcreteType, Type, stringify} from '../facade/lang';
import {ViewEncapsulation} from '../metadata';
import {AppModuleMetadata} from '../metadata/app_module';
import {NgModuleMetadata} from '../metadata/ng_module';
import {AppModuleFactory} from './app_module_factory';
import {ComponentFactory} from './component_factory';
import {ComponentResolver} from './component_resolver';
import {NgModuleFactory} from './ng_module_factory';
/**
@ -32,14 +33,16 @@ export class ComponentStillLoadingError extends BaseException {
* to create {@link ComponentFactory}s, which
* can later be used to create and render a Component instance.
*
* Each `@AppModule` provides an own `Compiler` to its injector,
* that will use the directives/pipes of the app module for compilation
* Each `@NgModule` provides an own `Compiler` to its injector,
* that will use the directives/pipes of the ng module for compilation
* of components.
* @stable
*/
export class Compiler {
/**
* Returns the injector with which the compiler has been created.
*
* @internal
*/
get injector(): Injector {
throw new BaseException(`Runtime compiler is not loaded. Tried to read the injector.`);
@ -48,7 +51,8 @@ export class Compiler {
/**
* Loads the template and styles of a component and returns the associated `ComponentFactory`.
*/
compileComponentAsync<T>(component: ConcreteType<T>): Promise<ComponentFactory<T>> {
compileComponentAsync<T>(component: ConcreteType<T>, ngModule: Type = null):
Promise<ComponentFactory<T>> {
throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(component)}`);
}
@ -56,23 +60,21 @@ export class Compiler {
* Compiles the given component. All templates have to be either inline or compiled via
* `compileComponentAsync` before. Otherwise throws a {@link ComponentStillLoadingError}.
*/
compileComponentSync<T>(component: ConcreteType<T>): ComponentFactory<T> {
compileComponentSync<T>(component: ConcreteType<T>, ngModule: Type = null): ComponentFactory<T> {
throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(component)}`);
}
/**
* Compiles the given App Module. All templates of the components listed in `precompile`
* Compiles the given NgModule. All templates of the components listed in `precompile`
* have to be either inline or compiled before via `compileComponentAsync` /
* `compileAppModuleAsync`. Otherwise throws a {@link ComponentStillLoadingError}.
* `compileModuleAsync`. Otherwise throws a {@link ComponentStillLoadingError}.
*/
compileAppModuleSync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
AppModuleFactory<T> {
compileModuleSync<T>(moduleType: ConcreteType<T>): NgModuleFactory<T> {
throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(moduleType)}`);
}
compileAppModuleAsync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
Promise<AppModuleFactory<T>> {
compileModuleAsync<T>(moduleType: ConcreteType<T>): Promise<NgModuleFactory<T>> {
throw new BaseException(
`Runtime compiler is not loaded. Tried to compile ${stringify(moduleType)}`);
}
@ -83,7 +85,7 @@ export class Compiler {
clearCache(): void {}
/**
* Clears the cache for the given component/appModule.
* Clears the cache for the given component/ngModule.
*/
clearCacheFor(type: Type) {}
}
@ -98,8 +100,14 @@ export type CompilerOptions = {
useJit?: boolean,
defaultEncapsulation?: ViewEncapsulation,
providers?: any[],
deprecatedAppProviders?: any[]
}
};
/**
* Token to provide CompilerOptions in the platform injector.
*
* @experimental
*/
export const CompilerOptions = new OpaqueToken('compilerOptions');
/**
* A factory for creating a Compiler
@ -107,44 +115,5 @@ export type CompilerOptions = {
* @experimental
*/
export abstract class CompilerFactory {
static mergeOptions(defaultOptions: CompilerOptions = {}, newOptions: CompilerOptions = {}):
CompilerOptions {
return {
useDebug: _firstDefined(newOptions.useDebug, defaultOptions.useDebug),
useJit: _firstDefined(newOptions.useJit, defaultOptions.useJit),
defaultEncapsulation:
_firstDefined(newOptions.defaultEncapsulation, defaultOptions.defaultEncapsulation),
providers: _mergeArrays(defaultOptions.providers, newOptions.providers),
deprecatedAppProviders:
_mergeArrays(defaultOptions.deprecatedAppProviders, newOptions.deprecatedAppProviders)
};
}
withDefaults(options: CompilerOptions = {}): CompilerFactory {
return new _DefaultApplyingCompilerFactory(this, options);
}
abstract createCompiler(options?: CompilerOptions): Compiler;
}
class _DefaultApplyingCompilerFactory extends CompilerFactory {
constructor(private _delegate: CompilerFactory, private _options: CompilerOptions) { super(); }
createCompiler(options: CompilerOptions = {}): Compiler {
return this._delegate.createCompiler(CompilerFactory.mergeOptions(this._options, options));
}
}
function _firstDefined<T>(...args: T[]): T {
for (var i = 0; i < args.length; i++) {
if (args[i] !== undefined) {
return args[i];
}
}
return undefined;
}
function _mergeArrays(...parts: any[][]): any[] {
let result: any[] = [];
parts.forEach((part) => result.push.apply(result, part));
return result;
abstract createCompiler(options?: CompilerOptions[]): Compiler;
}

View File

@ -6,12 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Console} from '../console';
import {Injectable} from '../di/decorators';
import {PromiseWrapper} from '../facade/async';
import {BaseException} from '../facade/exceptions';
import {Type, isBlank, isString, stringify} from '../facade/lang';
import {reflector} from '../reflection/reflection';
import {Type} from '../facade/lang';
import {ComponentFactory} from './component_factory';
/**
@ -19,43 +14,17 @@ import {ComponentFactory} from './component_factory';
* can later be used to create and render a Component instance.
*
* @deprecated Use {@link ComponentFactoryResolver} together with {@link
* AppModule}.precompile}/{@link Component}.precompile or
* NgModule}.precompile}/{@link Component}.precompile or
* {@link ANALYZE_FOR_PRECOMPILE} provider for dynamic component creation.
* Use {@link AppModuleFactoryLoader} for lazy loading.
* Use {@link NgModuleFactoryLoader} for lazy loading.
*/
export abstract class ComponentResolver {
static DynamicCompilationDeprecationMsg =
'ComponentResolver is deprecated for dynamic compilation. Use ComponentFactoryResolver together with @AppModule/@Component.precompile or ANALYZE_FOR_PRECOMPILE provider instead.';
'ComponentResolver is deprecated for dynamic compilation. Use ComponentFactoryResolver together with @NgModule/@Component.precompile or ANALYZE_FOR_PRECOMPILE provider instead. For runtime compile only, you can also use Compiler.compileComponentSync/Async.';
static LazyLoadingDeprecationMsg =
'ComponentResolver is deprecated for lazy loading. Use AppModuleFactoryLoader instead.';
'ComponentResolver is deprecated for lazy loading. Use NgModuleFactoryLoader instead.';
abstract resolveComponent(component: Type|string): Promise<ComponentFactory<any>>;
abstract clearCache(): void;
}
function _isComponentFactory(type: any): boolean {
return type instanceof ComponentFactory;
}
@Injectable()
export class ReflectorComponentResolver extends ComponentResolver {
constructor(private _console: Console) { super(); }
resolveComponent(component: Type|string): Promise<ComponentFactory<any>> {
if (isString(component)) {
return PromiseWrapper.reject(
new BaseException(`Cannot resolve component using '${component}'.`), null);
}
this._console.warn(ComponentResolver.DynamicCompilationDeprecationMsg);
var metadatas = reflector.annotations(<Type>component);
var componentFactory = metadatas.find(_isComponentFactory);
if (isBlank(componentFactory)) {
throw new BaseException(`No precompiled component ${stringify(component)} found`);
}
return PromiseWrapper.resolve(componentFactory);
}
clearCache() {}
}

View File

@ -8,13 +8,15 @@
import {Injectable, Injector, ReflectiveInjector, ResolvedReflectiveProvider} from '../di';
import {Type, isPresent} from '../facade/lang';
import {Compiler} from './compiler';
import {ComponentRef} from './component_factory';
import {ComponentResolver} from './component_resolver';
import {ViewContainerRef} from './view_container_ref';
/**
* Use ComponentResolver and ViewContainerRef directly.
* Use ComponentFactoryResolver and ViewContainerRef directly.
*
* @deprecated
*/
@ -119,12 +121,12 @@ export abstract class DynamicComponentLoader {
@Injectable()
export class DynamicComponentLoader_ extends DynamicComponentLoader {
constructor(private _compiler: ComponentResolver) { super(); }
constructor(private _compiler: Compiler) { super(); }
loadAsRoot(
type: Type, overrideSelectorOrNode: string|any, injector: Injector, onDispose?: () => void,
projectableNodes?: any[][]): Promise<ComponentRef<any>> {
return this._compiler.resolveComponent(type).then(componentFactory => {
return this._compiler.compileComponentAsync(<any>type).then(componentFactory => {
var componentRef = componentFactory.create(
injector, projectableNodes,
isPresent(overrideSelectorOrNode) ? overrideSelectorOrNode : componentFactory.selector);
@ -138,7 +140,7 @@ export class DynamicComponentLoader_ extends DynamicComponentLoader {
loadNextToLocation(
type: Type, location: ViewContainerRef, providers: ResolvedReflectiveProvider[] = null,
projectableNodes: any[][] = null): Promise<ComponentRef<any>> {
return this._compiler.resolveComponent(type).then(componentFactory => {
return this._compiler.compileComponentAsync(<any>type).then(componentFactory => {
var contextInjector = location.parentInjector;
var childInjector = isPresent(providers) && providers.length > 0 ?
ReflectiveInjector.fromResolvedProviders(providers, contextInjector) :

View File

@ -14,15 +14,16 @@ import {CodegenComponentFactoryResolver, ComponentFactoryResolver} from './compo
/**
* Represents an instance of an AppModule created via a {@link AppModuleFactory}.
* Represents an instance of an NgModule created via a {@link NgModuleFactory}.
*
* `AppModuleRef` provides access to the AppModule Instance as well other objects related to this
* AppModule Instance.
* @stable
* `NgModuleRef` provides access to the NgModule Instance as well other objects related to this
* NgModule Instance.
*
* @experimental
*/
export abstract class AppModuleRef<T> {
export abstract class NgModuleRef<T> {
/**
* The injector that contains all of the providers of the AppModule.
* The injector that contains all of the providers of the NgModule.
*/
get injector(): Injector { return unimplemented(); }
@ -33,22 +34,22 @@ export abstract class AppModuleRef<T> {
get componentFactoryResolver(): ComponentFactoryResolver { return unimplemented(); }
/**
* The AppModule instance.
* The NgModule instance.
*/
get instance(): T { return unimplemented(); }
}
/**
* @stable
* @experimental
*/
export class AppModuleFactory<T> {
export class NgModuleFactory<T> {
constructor(
private _injectorClass: {new (parentInjector: Injector): AppModuleInjector<T>},
private _injectorClass: {new (parentInjector: Injector): NgModuleInjector<T>},
private _moduleype: ConcreteType<T>) {}
get moduleType(): ConcreteType<T> { return this._moduleype; }
create(parentInjector: Injector = null): AppModuleRef<T> {
create(parentInjector: Injector): NgModuleRef<T> {
if (!parentInjector) {
parentInjector = Injector.NULL;
}
@ -60,9 +61,9 @@ export class AppModuleFactory<T> {
const _UNDEFINED = new Object();
export abstract class AppModuleInjector<T> extends CodegenComponentFactoryResolver implements
export abstract class NgModuleInjector<T> extends CodegenComponentFactoryResolver implements
Injector,
AppModuleRef<T> {
NgModuleRef<T> {
public instance: T;
constructor(public parent: Injector, factories: ComponentFactory<any>[]) {

View File

@ -6,12 +6,12 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AppModuleFactory} from './app_module_factory';
import {NgModuleFactory} from './ng_module_factory';
/**
* Used to load app moduled factories.
* Used to load ng moduled factories.
* @experimental
*/
export abstract class AppModuleFactoryLoader {
abstract load(path: string): Promise<AppModuleFactory<any>>;
}
export abstract class NgModuleFactoryLoader {
abstract load(path: string): Promise<NgModuleFactory<any>>;
}

View File

@ -10,9 +10,9 @@
import {Injectable, Optional} from '../di';
import {global} from '../facade/lang';
import {AppModuleFactory} from './app_module_factory';
import {AppModuleFactoryLoader} from './app_module_factory_loader';
import {Compiler} from './compiler';
import {NgModuleFactory} from './ng_module_factory';
import {NgModuleFactoryLoader} from './ng_module_factory_loader';
const _SEPARATOR = '#';
@ -20,18 +20,18 @@ const FACTORY_MODULE_SUFFIX = '.ngfactory';
const FACTORY_CLASS_SUFFIX = 'NgFactory';
/**
* AppModuleFactoryLoader that uses SystemJS to load AppModuleFactory
* NgModuleFactoryLoader that uses SystemJS to load NgModuleFactory
* @experimental
*/
@Injectable()
export class SystemJsAppModuleLoader implements AppModuleFactoryLoader {
export class SystemJsNgModuleLoader implements NgModuleFactoryLoader {
constructor(@Optional() private _compiler: Compiler) {}
load(path: string): Promise<AppModuleFactory<any>> {
load(path: string): Promise<NgModuleFactory<any>> {
return this._compiler ? this.loadAndCompile(path) : this.loadFactory(path);
}
private loadAndCompile(path: string): Promise<AppModuleFactory<any>> {
private loadAndCompile(path: string): Promise<NgModuleFactory<any>> {
let [module, exportName] = path.split(_SEPARATOR);
if (exportName === undefined) exportName = 'default';
@ -39,10 +39,10 @@ export class SystemJsAppModuleLoader implements AppModuleFactoryLoader {
.System.import(module)
.then((module: any) => module[exportName])
.then((type: any) => checkNotEmpty(type, module, exportName))
.then((type: any) => this._compiler.compileAppModuleAsync(type));
.then((type: any) => this._compiler.compileModuleAsync(type));
}
private loadFactory(path: string): Promise<AppModuleFactory<any>> {
private loadFactory(path: string): Promise<NgModuleFactory<any>> {
let [module, exportName] = path.split(_SEPARATOR);
if (exportName === undefined) exportName = 'default';
@ -58,4 +58,4 @@ function checkNotEmpty(value: any, modulePath: string, exportName: string): any
throw new Error(`Cannot find '${exportName}' in '${modulePath}'`);
}
return value;
}
}

View File

@ -18,9 +18,9 @@ const _SEPARATOR = '#';
/**
* Component resolver that can load components lazily
*
* @deprecated Lazy loading of components is deprecated. Use {@link SystemJsAppModuleLoader} to lazy
* @deprecated Lazy loading of components is deprecated. Use {@link SystemJsNgModuleLoader} to lazy
* load
* {@link AppModuleFactory}s instead.
* {@link NgModuleFactory}s instead.
*/
@Injectable()
export class SystemJsComponentResolver implements ComponentResolver {
@ -53,9 +53,9 @@ const FACTORY_CLASS_SUFFIX = 'NgFactory';
/**
* Component resolver that can load component factories lazily
*
* @deprecated Lazy loading of components is deprecated. Use {@link SystemJsAppModuleLoader}
* @deprecated Lazy loading of components is deprecated. Use {@link SystemJsNgModuleLoader}
* to lazy
* load {@link AppModuleFactory}s instead.
* load {@link NgModuleFactory}s instead.
*/
@Injectable()
export class SystemJsCmpFactoryResolver implements ComponentResolver {