feat(browser): use AppModules for bootstrap in the browser
This introduces the `BrowserModule` to be used for long form bootstrap and offline compile bootstrap: ``` @AppModule({ modules: [BrowserModule], precompile: [MainComponent], providers: […], // additional providers directives: […], // additional platform directives pipes: […] // additional platform pipes }) class MyModule { constructor(appRef: ApplicationRef) { appRef.bootstrap(MainComponent); } } // offline compile import {bootstrapModuleFactory} from ‘@angular/platform-browser’; bootstrapModuleFactory(MyModuleNgFactory); // runtime compile long form import {bootstrapModule} from ‘@angular/platform-browser-dynamic’; bootstrapModule(MyModule); ``` The short form, `bootstrap(...)`, can now creates a module on the fly, given `directives`, `pipes, `providers`, `precompile` and `modules` properties. Related changes: - make `SanitizationService`, `SecurityContext` public in `@angular/core` so that the offline compiler can resolve the token - move `AnimationDriver` to `platform-browser` and make it public so that the offline compiler can resolve the token BREAKING CHANGES: - short form bootstrap does no longer allow to inject compiler internals (i.e. everything from `@angular/compiler). Inject `Compiler` instead. To provide custom providers for the compiler, create a custom compiler via `browserCompiler({providers: [...]})` and pass that into the `bootstrap` method.
This commit is contained in:
@ -38,6 +38,7 @@ import {Lexer} from './expression_parser/lexer';
|
||||
import {ViewResolver} from './view_resolver';
|
||||
import {DirectiveResolver} from './directive_resolver';
|
||||
import {PipeResolver} from './pipe_resolver';
|
||||
import {Console, Reflector, reflector, ReflectorReader} from '../core_private';
|
||||
|
||||
/**
|
||||
* A set of providers that provide `RuntimeCompiler` and its dependencies to use for
|
||||
@ -45,6 +46,9 @@ import {PipeResolver} from './pipe_resolver';
|
||||
*/
|
||||
export const COMPILER_PROVIDERS: Array<any|Type|{[k: string]: any}|any[]> =
|
||||
/*@ts2dart_const*/[
|
||||
{provide: Reflector, useValue: reflector},
|
||||
{provide: ReflectorReader, useExisting: Reflector},
|
||||
Console,
|
||||
Lexer,
|
||||
Parser,
|
||||
HtmlParser,
|
||||
|
@ -6,9 +6,9 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AppModuleFactory, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, QueryList, RenderComponentType, Renderer, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
||||
import {AppModuleFactory, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ElementRef, Injector, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
||||
|
||||
import {AnimationGroupPlayer as AnimationGroupPlayer_, AnimationKeyframe as AnimationKeyframe_, AnimationSequencePlayer as AnimationSequencePlayer_, AnimationStyles as AnimationStyles_, AppElement, AppModuleInjector, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, EMPTY_ARRAY, EMPTY_MAP, NoOpAnimationPlayer as NoOpAnimationPlayer_, SecurityContext, StaticNodeDebugInfo, TemplateRef_, ValueUnwrapper, ViewType, ViewUtils, balanceAnimationKeyframes as impBalanceAnimationKeyframes, castByValue, checkBinding, clearStyles as impClearStyles, collectAndResolveStyles as impCollectAndResolveStyles, devModeEqual, flattenNestedViewRenderNodes, interpolate, prepareFinalAnimationStyles as impBalanceAnimationStyles, pureProxy1, pureProxy10, pureProxy2, pureProxy3, pureProxy4, pureProxy5, pureProxy6, pureProxy7, pureProxy8, pureProxy9, renderStyles as impRenderStyles, uninitialized} from '../core_private';
|
||||
import {AnimationGroupPlayer as AnimationGroupPlayer_, AnimationKeyframe as AnimationKeyframe_, AnimationSequencePlayer as AnimationSequencePlayer_, AnimationStyles as AnimationStyles_, AppElement, AppModuleInjector, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, DebugAppView, DebugContext, EMPTY_ARRAY, EMPTY_MAP, NoOpAnimationPlayer as NoOpAnimationPlayer_, StaticNodeDebugInfo, TemplateRef_, ValueUnwrapper, ViewType, ViewUtils, balanceAnimationKeyframes as impBalanceAnimationKeyframes, castByValue, checkBinding, clearStyles as impClearStyles, collectAndResolveStyles as impCollectAndResolveStyles, devModeEqual, flattenNestedViewRenderNodes, interpolate, prepareFinalAnimationStyles as impBalanceAnimationStyles, pureProxy1, pureProxy10, pureProxy2, pureProxy3, pureProxy4, pureProxy5, pureProxy6, pureProxy7, pureProxy8, pureProxy9, renderStyles as impRenderStyles, uninitialized} from '../core_private';
|
||||
|
||||
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
|
||||
import {assetUrl} from './util';
|
||||
|
@ -196,29 +196,11 @@ export class CompileMetadataResolver {
|
||||
throw new BaseException(
|
||||
`Could not compile '${stringify(moduleType)}' because it is not an AppModule.`);
|
||||
}
|
||||
let providers: any[] = [];
|
||||
if (meta.providers) {
|
||||
providers.push(...this.getProvidersMetadata(meta.providers));
|
||||
}
|
||||
|
||||
let directives: cpl.CompileTypeMetadata[] = [];
|
||||
if (meta.directives) {
|
||||
directives.push(...flattenArray(meta.directives)
|
||||
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
|
||||
}
|
||||
|
||||
let pipes: cpl.CompileTypeMetadata[] = [];
|
||||
if (meta.pipes) {
|
||||
pipes.push(...flattenArray(meta.pipes)
|
||||
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
|
||||
}
|
||||
|
||||
let precompile: cpl.CompileTypeMetadata[] = [];
|
||||
if (meta.precompile) {
|
||||
precompile.push(...flattenArray(meta.precompile)
|
||||
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
|
||||
}
|
||||
let modules: cpl.CompileTypeMetadata[] = [];
|
||||
let providers: any[] = [];
|
||||
let directives: cpl.CompileTypeMetadata[] = [];
|
||||
let pipes: cpl.CompileTypeMetadata[] = [];
|
||||
let precompile: cpl.CompileTypeMetadata[] = [];
|
||||
if (meta.modules) {
|
||||
flattenArray(meta.modules).forEach((moduleType) => {
|
||||
var meta = this.getAppModuleMetadata(moduleType);
|
||||
@ -231,6 +213,22 @@ export class CompileMetadataResolver {
|
||||
});
|
||||
}
|
||||
|
||||
if (meta.providers) {
|
||||
providers.push(...this.getProvidersMetadata(meta.providers));
|
||||
}
|
||||
if (meta.directives) {
|
||||
directives.push(...flattenArray(meta.directives)
|
||||
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
|
||||
}
|
||||
if (meta.pipes) {
|
||||
pipes.push(...flattenArray(meta.pipes)
|
||||
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
|
||||
}
|
||||
if (meta.precompile) {
|
||||
precompile.push(...flattenArray(meta.precompile)
|
||||
.map(type => this.getTypeMetadata(type, staticTypeModuleUrl(type))));
|
||||
}
|
||||
|
||||
compileMeta = new cpl.CompileAppModuleMetadata({
|
||||
type: this.getTypeMetadata(moduleType, staticTypeModuleUrl(moduleType)),
|
||||
providers: providers,
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AppModuleFactory, AppModuleMetadata, Compiler, ComponentFactory, ComponentResolver, Injectable} from '@angular/core';
|
||||
import {AppModuleFactory, AppModuleMetadata, Compiler, ComponentFactory, ComponentResolver, Injectable, Provider} from '@angular/core';
|
||||
|
||||
import {BaseException} from '../src/facade/exceptions';
|
||||
import {ConcreteType, IS_DART, Type, isBlank, isString, stringify} from '../src/facade/lang';
|
||||
@ -76,6 +76,14 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
|
||||
let componentCompilePromises: Promise<any>[] = [];
|
||||
if (!appModuleFactory || !useCache) {
|
||||
var compileModuleMeta = this._metadataResolver.getAppModuleMetadata(moduleType, metadata);
|
||||
let boundCompiler = new BoundCompiler(
|
||||
this, compileModuleMeta.directives.map(dir => dir.type.runtime),
|
||||
compileModuleMeta.pipes.map((pipe) => pipe.type.runtime));
|
||||
// Always provide a bound Compiler / ComponentResolver
|
||||
compileModuleMeta.providers.push(this._metadataResolver.getProviderMetadata(
|
||||
new Provider(Compiler, {useValue: boundCompiler})));
|
||||
compileModuleMeta.providers.push(this._metadataResolver.getProviderMetadata(
|
||||
new Provider(ComponentResolver, {useExisting: Compiler})));
|
||||
var compileResult = this._appModuleCompiler.compile(compileModuleMeta);
|
||||
compileResult.dependencies.forEach((dep) => {
|
||||
let compileResult = this._compileComponent(
|
||||
@ -102,21 +110,18 @@ export class RuntimeCompiler implements ComponentResolver, Compiler {
|
||||
appModuleFactory, Promise.all(componentCompilePromises).then(() => appModuleFactory));
|
||||
}
|
||||
|
||||
compileComponentAsync<T>(compType: ConcreteType<T>, {moduleDirectives = [], modulePipes = []}: {
|
||||
moduleDirectives?: ConcreteType<any>[],
|
||||
modulePipes?: ConcreteType<any>[]
|
||||
} = {}): Promise<ComponentFactory<T>> {
|
||||
return this._compileComponent(compType, false, moduleDirectives, modulePipes).asyncResult;
|
||||
compileComponentAsync<T>(compType: ConcreteType<T>): Promise<ComponentFactory<T>> {
|
||||
return this._compileComponent(compType, false, [], []).asyncResult;
|
||||
}
|
||||
|
||||
compileComponentSync<T>(compType: ConcreteType<T>, {moduleDirectives = [], modulePipes = []}: {
|
||||
moduleDirectives?: ConcreteType<any>[],
|
||||
modulePipes?: ConcreteType<any>[]
|
||||
} = {}): ComponentFactory<T> {
|
||||
return this._compileComponent(compType, true, moduleDirectives, modulePipes).syncResult;
|
||||
compileComponentSync<T>(compType: ConcreteType<T>): ComponentFactory<T> {
|
||||
return this._compileComponent(compType, true, [], []).syncResult;
|
||||
}
|
||||
|
||||
private _compileComponent<T>(
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
_compileComponent<T>(
|
||||
compType: ConcreteType<T>, isSync: boolean, moduleDirectives: ConcreteType<any>[],
|
||||
modulePipes: ConcreteType<any>[]): SyncAsyncResult<ComponentFactory<T>> {
|
||||
var templates =
|
||||
@ -343,3 +348,50 @@ function assertComponent(meta: CompileDirectiveMetadata) {
|
||||
throw new BaseException(`Could not compile '${meta.type.name}' because it is not a component.`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around `Compiler` and `ComponentResolver` that
|
||||
* provides default patform directives / pipes.
|
||||
*/
|
||||
class BoundCompiler implements Compiler, ComponentResolver {
|
||||
constructor(
|
||||
private _delegate: RuntimeCompiler, private _directives: any[], private _pipes: any[]) {}
|
||||
|
||||
resolveComponent(component: Type|string): Promise<ComponentFactory<any>> {
|
||||
if (isString(component)) {
|
||||
return PromiseWrapper.reject(
|
||||
new BaseException(`Cannot resolve component using '${component}'.`), null);
|
||||
}
|
||||
return this.compileComponentAsync(<ConcreteType<any>>component);
|
||||
}
|
||||
|
||||
compileComponentAsync<T>(compType: ConcreteType<T>): Promise<ComponentFactory<T>> {
|
||||
return this._delegate._compileComponent(compType, false, this._directives, this._pipes)
|
||||
.asyncResult;
|
||||
}
|
||||
|
||||
compileComponentSync<T>(compType: ConcreteType<T>): ComponentFactory<T> {
|
||||
return this._delegate._compileComponent(compType, true, this._directives, this._pipes)
|
||||
.syncResult;
|
||||
}
|
||||
|
||||
compileAppModuleSync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
|
||||
AppModuleFactory<T> {
|
||||
return this._delegate.compileAppModuleSync(moduleType, metadata);
|
||||
}
|
||||
|
||||
compileAppModuleAsync<T>(moduleType: ConcreteType<T>, metadata: AppModuleMetadata = null):
|
||||
Promise<AppModuleFactory<T>> {
|
||||
return this._delegate.compileAppModuleAsync(moduleType, metadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all caches
|
||||
*/
|
||||
clearCache(): void { this._delegate.clearCache(); }
|
||||
|
||||
/**
|
||||
* Clears the cache for the given component/appModule.
|
||||
*/
|
||||
clearCacheFor(type: Type) { this._delegate.clearCacheFor(type); }
|
||||
}
|
@ -6,9 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Injectable, SecurityContext} from '@angular/core';
|
||||
|
||||
import {SecurityContext} from '../../core_private';
|
||||
import {StringMapWrapper} from '../facade/collection';
|
||||
import {isPresent} from '../facade/lang';
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {SecurityContext} from '../../core_private';
|
||||
import {SecurityContext} from '@angular/core';
|
||||
|
||||
// =================================================================================================
|
||||
// =================================================================================================
|
||||
|
@ -12,7 +12,7 @@ import {AST} from './expression_parser/ast';
|
||||
|
||||
import {CompileDirectiveMetadata, CompileTokenMetadata, CompileProviderMetadata,} from './compile_metadata';
|
||||
import {ParseSourceSpan} from './parse_util';
|
||||
import {SecurityContext} from '../core_private';
|
||||
import {SecurityContext} from '@angular/core';
|
||||
|
||||
/**
|
||||
* An Abstract Syntax Tree node representing part of a parsed Angular template.
|
||||
|
@ -6,9 +6,9 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Inject, Injectable, OpaqueToken, Optional} from '@angular/core';
|
||||
import {Inject, Injectable, OpaqueToken, Optional, SecurityContext} from '@angular/core';
|
||||
|
||||
import {Console, MAX_INTERPOLATION_VALUES, SecurityContext} from '../core_private';
|
||||
import {Console, MAX_INTERPOLATION_VALUES} from '../core_private';
|
||||
|
||||
import {ListWrapper, StringMapWrapper, SetWrapper,} from '../src/facade/collection';
|
||||
import {RegExpWrapper, isPresent, StringWrapper, isBlank, isArray} from '../src/facade/lang';
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {EMPTY_STATE as EMPTY_ANIMATION_STATE, LifecycleHooks, SecurityContext, isDefaultChangeDetectionStrategy} from '../../core_private';
|
||||
import {EMPTY_STATE as EMPTY_ANIMATION_STATE, LifecycleHooks, isDefaultChangeDetectionStrategy} from '../../core_private';
|
||||
import * as cdAst from '../expression_parser/ast';
|
||||
import {isBlank, isPresent} from '../facade/lang';
|
||||
import {Identifiers} from '../identifiers';
|
||||
@ -25,7 +25,7 @@ import {camelCaseToDashCase} from '../util';
|
||||
import {convertCdExpressionToIr} from './expression_converter';
|
||||
|
||||
import {CompileBinding} from './compile_binding';
|
||||
import {BaseException} from '@angular/core';
|
||||
import {BaseException, SecurityContext} from '@angular/core';
|
||||
|
||||
|
||||
function createBindFieldExpr(exprIndex: number): o.ReadPropExpr {
|
||||
|
Reference in New Issue
Block a user