试读angular源码第四章:angular模块及JIT编译模块
栏目: JavaScript · 发布时间: 5年前
NgModule
是一个带有 @NgModule
装饰器的类。
@NgModule
的参数是一个元数据对象,用于描述如何编译组件的模板,以及如何在运行时创建注入器。
它会标出该模块自己的组件、指令和管道,通过 exports
属性公开其中的一部分,以便外部组件使用它们。
NgModule
还能把一些服务提供商添加到应用的依赖注入器中。
在之前的例子中,我们通过 platformBrowserDynamic().bootstrapModule(AppModule).catch(err => console.error(err));
引导初始化时, bootstrapModule
方法传入的第一个参数就是angular 模块 NgModule
。
这里我们要先讲2个概念:JIT 和 AOT
JIT和AOT
Angular 提供了两种方式来编译你的应用:
- 即时编译 (JIT Just-In-Time),它会在运行期间在浏览器中编译你的应用
- 预先(AOT Ahead-Of-Time)编译,它会在构建时编译你的应用
-
JIT的流程
- 编译时
- 运行 ngc(angular 封装的 tsc) 编译 TypeScript 代码为 JavaScript 并提取元数据
- 构建项目,做些代码打包、混淆、压缩
- 部署应用
- 浏览器运行时
- 浏览器下载 JavaScript 代码
- 启动 angular 应用
- angular 启动 jit 编译模式,编译指令组件模块提取 ngc 编译出元数据
- 创建各种指令组件模块的实例,产生视图
- 编译时
-
AOT的流程
- 代码分析阶段
.metadata.json
- 浏览器运行时
- 浏览器下载 JavaScript 代码
- 启动 angular 应用,产生视图
- 代码分析阶段
但这里我们只讨论 JIT 模式!
@NgModule
angular/packages/core/src/metadata/ng_module.ts
export interface NgModuleDecorator { (obj?: NgModule): TypeDecorator; new (obj?: NgModule): NgModule; } export interface NgModule { providers?: Provider[]; declarations?: Array<Type<any>|any[]>; imports?: Array<Type<any>|ModuleWithProviders<{}>|any[]>; exports?: Array<Type<any>|any[]>; entryComponents?: Array<Type<any>|any[]>; bootstrap?: Array<Type<any>|any[]>; schemas?: Array<SchemaMetadata|any[]>; id?: string; jit?: true; } /** * @Annotation * @publicApi */ export const NgModule: NgModuleDecorator = makeDecorator( 'NgModule', (ngModule: NgModule) => ngModule, undefined, undefined, /** * Decorator that marks the following class as an NgModule, and supplies * configuration metadata for it. * * * The `declarations` and `entryComponents` options configure the compiler * with information about what belongs to the NgModule. * * The `providers` options configures the NgModule's injector to provide * dependencies the NgModule members. * * The `imports` and `exports` options bring in members from other modules, and make * this module's members available to others. */ (type: NgModuleType, meta: NgModule) => SWITCH_COMPILE_NGMODULE(type, meta)); 复制代码
装饰器 @NgModule
的作用是描述 angular 模块,并提供元数据 支持
例如几个常用的元数据:
-
providers?: Provider[];
依赖注入系统提供可注入项的重点- 非懒加载模块定义的
providers
可以提供给全局任何指令管道服务 ,相当于@Injectable
为root
- 懒加载的模块 有自己的注入器,通常是 app root 注入器的子注入器 ,在 懒加载模块内为单例服务
- 非懒加载模块定义的
-
declarations
属于此模块的组件,指令和管道的集合 -
imports
引入其他模块的export
-
exports
到处给其他模块的imports
-
bootstrap
引导用的入口组件,通常 根模块和路由懒加载需要设置 -
entryComponents
入口组件 不常用,angular 编译器会自动将bootstrap
编译到里面
而 @NgModule
由 makeDecorator
构造而来:
makeDecorator创建装饰器
makeDecorator
用来创建 angular 装饰器,像 @NgModule
@Component
@Pipe
@Directive
都用改方法创建:
angular/packages/core/src/util/decorators.ts
export const ANNOTATIONS = '__annotations__'; export function makeDecorator<T>( name: string, props?: (...args: any[]) => any, // 注释:args 就是装饰器的参数用来处理装饰器参数 parentClass?: any, additionalProcessing?: (type: Type<T>) => void, // 注释:额外的处理 typeFn?: (type: Type<T>, ...args: any[]) => void) // 注释:用来处理class的原型 : {new (...args: any[]): any; (...args: any[]): any; (...args: any[]): (cls: any) => any;} { const metaCtor = makeMetadataCtor(props); // 注释:创建 Metadata 的构造函数 function DecoratorFactory(...args: any[]): (cls: Type<T>) => any { if (this instanceof DecoratorFactory) { // 注释:通过 args 用来设置默认值 metaCtor.call(this, ...args); // 注释:this就是DecoratorFactory工厂,也就是参数对象 return this; } const annotationInstance = new (DecoratorFactory as any)(...args); // 注释:注解实例实际上就是装饰器的参数对象 return function TypeDecorator(cls: Type<T>) { // 注释:cls就是装饰器装饰的类构造函数 if (typeFn) typeFn(cls, ...args); // Use of Object.defineProperty is important since it creates non-enumerable property which // prevents the property is copied during subclassing. const annotations = cls.hasOwnProperty(ANNOTATIONS) ? (cls as any)[ANNOTATIONS] : Object.defineProperty(cls, ANNOTATIONS, {value: []})[ANNOTATIONS]; annotations.push(annotationInstance); // 注释:将装饰器的处理结果存在 if (additionalProcessing) additionalProcessing(cls); return cls; }; } if (parentClass) { DecoratorFactory.prototype = Object.create(parentClass.prototype); // 注释:使实例 DecoratorFactory 继承继承 parentClass } DecoratorFactory.prototype.ngMetadataName = name; // 注释:装饰器名称会被放在原型属性 ngMetadataName 上 (DecoratorFactory as any).annotationCls = DecoratorFactory; return DecoratorFactory as any; } function makeMetadataCtor(props?: (...args: any[]) => any): any { return function ctor(...args: any[]) { if (props) { const values = props(...args); for (const propName in values) { this[propName] = values[propName]; } } }; } 复制代码
参数:
-
name: string
就是装饰器的名称 -
props?: (...args: any[]) => any
args
就是装饰器的参数,props
用来处理装饰器参数, 可用于默认值设置 -
parentClass?: any
父类,提供给DecoratorFactory
实例用来继承 -
additionalProcessing?: (type: Type<T>) => void
对类构造函数进行额外处理, 参数是装饰器的宿主类的构造函数 -
typeFn?: (type: Type<T>, ...args: any[]) => void)
在装饰器的返回函数中,会再次执行下回调函数,参数是 类构造函数和参数
在这里 makeDecorator
基本上做了这几个事情:
- 通过
makeMetadataCtor
创建一个 给类构造函数附加初始值的函数 ,本质上是 创建 Metadata 的构造函数 - 如果
this
是注解工厂DecoratorFactory
的实例,则通过上面给类构造函数附加初始值的函数,传入this
和装饰器参数args
- 此外则先执行
typeFn
传入类构造函数和参数,修改类构造函数 - 先传入 参数创建注解工厂
DecoratorFactory
的实例 ,注解工厂方法会递归执行,直到this
是注解工厂DecoratorFactory
的实例 ( 注解工厂DecoratorFactory
的实例实际上就是装饰器的参数对象 ) - 判断类构造函数是否存在
__annotations__:any[]
属性,把 装饰器处理结果(注解实例===参数对象)保存在类构造函数的__annotations__:any[]
属性数组中 ,并提供给编译器compiler
使用 - 最后通过处理
DecoratorFactory
的原型,继承父类parentClass
并添加元数据的名字ngMetadataName
注意这里: DecoratorFactory.prototype = Object.create(parentClass.prototype);
通过使用 Object.create
避免执行一次 parentClass
来继承父类
@NgModule总结
- 实际上,
makeDecorator
的作用就是 构造返回一个函数DecoratorFactory
用作装饰器,并 创建装饰器工厂DecoratorFactory
实例 - 其实,我觉得
@NgModule
就是一个接受参数并返回函数的方法, 装饰器会把@NgModule
传入的元数据对象进行处理并生成注解工厂DecoratorFactory
的实例挂在到__annotations__:any
提供给编译器使用 。
划重点: AppModule.__annotations__
:
最后大家可以 打印下 (AppModule as any).__annotations__
来进行验证 ,这就是存在模块类上的注解实例。
编译模块
此处建议结合 第二章bootstrapModule 一起阅读
JIT编译器的服务
先看下之前构建的 JitCompilerFactory
时注入过的服务,这些在后面编译的时候会大量用到:
angular/packages/platform-browser-dynamic/src/compiler_factory.ts
/** * A set of providers that provide `JitCompiler` and its dependencies to use for * template compilation. */ export const COMPILER_PROVIDERS = <StaticProvider[]>[ // 注释:这里也是一个核心点-编译反射器 {provide: CompileReflector, useValue: new JitReflector()}, // 注释:ResourceLoader- 资源加载器 {provide: ResourceLoader, useValue: _NO_RESOURCE_LOADER}, // 注释:jit 摘要解析器 {provide: JitSummaryResolver, deps: []}, // 注释:摘要解析器 {provide: SummaryResolver, useExisting: JitSummaryResolver}, {provide: Console, deps: []}, // 注释:语法分析器 {provide: Lexer, deps: []}, // 注释:解析器器 {provide: Parser, deps: [Lexer]}, // 注释:基本的HTML解析器 { provide: baseHtmlParser, useClass: HtmlParser, deps: [], }, // 注释:国际化的HTML解析器 { provide: I18NHtmlParser, useFactory: (parser: HtmlParser, translations: string | null, format: string, config: CompilerConfig, console: Console) => { translations = translations || ''; const missingTranslation = translations ? config.missingTranslation ! : MissingTranslationStrategy.Ignore; // 注释:new 国际化的HTML解析器 return new I18NHtmlParser(parser, translations, format, missingTranslation, console); }, deps: [ baseHtmlParser, [new Optional(), new Inject(TRANSLATIONS)], [new Optional(), new Inject(TRANSLATIONS_FORMAT)], [CompilerConfig], [Console], ] }, { provide: HtmlParser, useExisting: I18NHtmlParser, }, // 注释:模板解析器 { provide: TemplateParser, deps: [CompilerConfig, CompileReflector, Parser, ElementSchemaRegistry, I18NHtmlParser, Console] }, { provide: JitEvaluator, useClass: JitEvaluator, deps: [] }, // 注释:指令规范器 { provide: DirectiveNormalizer, deps: [ResourceLoader, UrlResolver, HtmlParser, CompilerConfig]}, // 注释:元数据解析器 { provide: CompileMetadataResolver, deps: [CompilerConfig, HtmlParser, NgModuleResolver, DirectiveResolver, PipeResolver, SummaryResolver, ElementSchemaRegistry, DirectiveNormalizer, Console, [Optional, StaticSymbolCache], CompileReflector, [Optional, ERROR_COLLECTOR_TOKEN]]}, DEFAULT_PACKAGE_URL_PROVIDER, // 注释:样式编译器 { provide: StyleCompiler, deps: [UrlResolver]}, // 注释:view 编译器 { provide: ViewCompiler, deps: [CompileReflector]}, // 注释:NgModule编译器 { provide: NgModuleCompiler, deps: [CompileReflector] }, // 注释:编译器配置项目 { provide: CompilerConfig, useValue: new CompilerConfig()}, // 注释:JIT时,Compiler的服务供应商 CompilerImpl { provide: Compiler, useClass: CompilerImpl, deps: [Injector, CompileMetadataResolver, TemplateParser, StyleCompiler, ViewCompiler, NgModuleCompiler, SummaryResolver, CompileReflector, JitEvaluator, CompilerConfig, Console]}, // 注释:DOM schema { provide: DomElementSchemaRegistry, deps: []}, // 注释:Element schema { provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry}, // 注释:URL解析器 { provide: UrlResolver, deps: [PACKAGE_ROOT_URL]}, // 注释:指令解析器 { provide: DirectiveResolver, deps: [CompileReflector]}, // 注释:管道解析器 { provide: PipeResolver, deps: [CompileReflector]}, // 注释:模块解析器 { provide: NgModuleResolver, deps: [CompileReflector]}, ]; 复制代码
讲完了 @NgModule
,回到之前的文章,看下 bootstrapModule
这个方法如何编译模块:
angular/packages/core/src/application_ref.ts
let compileNgModuleFactory: <M>(injector: Injector, options: CompilerOptions, moduleType: Type<M>) => Promise<NgModuleFactory<M>> = compileNgModuleFactory__PRE_R3__; function compileNgModuleFactory__PRE_R3__<M>( injector: Injector, options: CompilerOptions, moduleType: Type<M>): Promise<NgModuleFactory<M>> { const compilerFactory: CompilerFactory = injector.get(CompilerFactory); const compiler = compilerFactory.createCompiler([options]); return compiler.compileModuleAsync(moduleType); } @Injectable() export class PlatformRef { ... bootstrapModule<M>(moduleType: Type<M>, compilerOptions: (CompilerOptions&BootstrapOptions)| Array<CompilerOptions&BootstrapOptions> = []):Promise<NgModuleRef<M>> { const options = optionsReducer({}, compilerOptions); return compileNgModuleFactory(this.injector, options, moduleType) .then(moduleFactory => this.bootstrapModuleFactory(moduleFactory, options)); } ... } 复制代码
bootstrapModule
调用了 compileNgModuleFactory
这个方法,而最后其实在 JIT 模式下,其实 是 coreDynamic
提供的 JitCompilerFactory
创建了 CompilerImpl
实例并创建了代理 JitCompiler
去实现真正的编译 。
angular/packages/platform-browser-dynamic/src/compiler_factory.ts
export class CompilerImpl implements Compiler { ... private _delegate: JitCompiler; ... constructor( injector: Injector, private _metadataResolver: CompileMetadataResolver, templateParser: TemplateParser, styleCompiler: StyleCompiler, viewCompiler: ViewCompiler, ngModuleCompiler: NgModuleCompiler, summaryResolver: SummaryResolver<Type<any>>, compileReflector: CompileReflector, jitEvaluator: JitEvaluator, compilerConfig: CompilerConfig, console: Console) { // 注释:创建 JIT 编译器 this._delegate = new JitCompiler( _metadataResolver, templateParser, styleCompiler, viewCompiler, ngModuleCompiler, summaryResolver, compileReflector, jitEvaluator, compilerConfig, console, this.getExtraNgModuleProviders.bind(this)); } compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>> { // 注释:异步创建模块及其子组件 return this._delegate.compileModuleAsync(moduleType) as Promise<NgModuleFactory<T>>; } ... } 复制代码
最终由 JitCompiler
执行 compileModuleAsync
方法编译模块
JitCompiler
编译模块和组件的实际工作是由 CompilerImpl
交由代理 JitCompiler
的方法 compileModuleAsync<T>(moduleType: Type<T>)
完成的:
angular/packages/compiler/src/jit/compiler.ts
export class JitCompiler { private _compiledTemplateCache = new Map<Type, CompiledTemplate>(); private _compiledHostTemplateCache = new Map<Type, CompiledTemplate>(); private _compiledDirectiveWrapperCache = new Map<Type, Type>(); private _compiledNgModuleCache = new Map<Type, object>(); private _sharedStylesheetCount = 0; private _addedAotSummaries = new Set<() => any[]>(); constructor( private _metadataResolver: CompileMetadataResolver, private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler, private _ngModuleCompiler: NgModuleCompiler, private _summaryResolver: SummaryResolver<Type>, private _reflector: CompileReflector, private _jitEvaluator: JitEvaluator, private _compilerConfig: CompilerConfig, private _console: Console, private getExtraNgModuleProviders: (ngModule: any) => CompileProviderMetadata[]) { ... } ... compileModuleAsync(moduleType: Type): Promise<object> { // 注释:其实 JTI 编译在这步做的 return Promise.resolve(this._compileModuleAndComponents(moduleType, false)); } // 注释:做了三件事: // 1. 加载模块 `this._loadModules` // 2. 编译入口组件 `this._compileComponents` // 3. 编译模块 `this._compileModule` private _compileModuleAndComponents(moduleType: Type, isSync: boolean): SyncAsync<object> { // 注释:其实调用的是这步,编译主模块和组件 return SyncAsync.then(this._loadModules(moduleType, isSync), () => { // 注释:先加载模块 this._compileComponents(moduleType, null); // 注释:异步有结果之后的回调函数,编译主模块上的所有入口组件 return this._compileModule(moduleType); // 注释:返回编译后的模块工厂 }); } ... } 复制代码
结合第二章引导模块总结下:
compileModuleAsync
在这里只做了三件事:
this._loadModules this._compileComponents this._compileModule
_loadModules加载模块
angular/packages/compiler/src/jit/compiler.ts
export class JitCompiler { ... // 注释:异步加载解析主模块,也就是 bootstrap 的 ngModule private _loadModules(mainModule: any, isSync: boolean): SyncAsync<any> { const loading: Promise<any>[] = []; // 注释:从元数据中获得根模块的 __annotations__ 并格式化 const mainNgModule = this._metadataResolver.getNgModuleMetadata(mainModule) !; // 注释:过滤 AOT 模块并异步编加载数据中全部指令组件和和管道 // 注释:过滤掉根模块元数据中的 AOT 模块 this._filterJitIdentifiers(mainNgModule.transitiveModule.modules).forEach((nestedNgModule) => { // getNgModuleMetadata only returns null if the value passed in is not an NgModule const moduleMeta = this._metadataResolver.getNgModuleMetadata(nestedNgModule) !; this._filterJitIdentifiers(moduleMeta.declaredDirectives).forEach((ref) => { // 注释:异步编加载数据中全部指令组件和和管道 const promise = this._metadataResolver.loadDirectiveMetadata(moduleMeta.type.reference, ref, isSync); if (promise) { loading.push(promise); } }); this._filterJitIdentifiers(moduleMeta.declaredPipes) .forEach((ref) => this._metadataResolver.getOrLoadPipeMetadata(ref)); }); // 注释:最后全部并行 Promise return SyncAsync.all(loading); } ... // 注释:过滤掉根模块元数据中的 AOT 模块 hasAotSummary(ref: Type) { return !!this._summaryResolver.resolveSummary(ref); } // 注释:过滤掉根模块元数据中的 AOT 模块 private _filterJitIdentifiers(ids: CompileIdentifierMetadata[]): any[] { return ids.map(mod => mod.reference).filter((ref) => !this.hasAotSummary(ref)); } } 复制代码
_loadModules
接受2个参数:
-
mainModule: any
模块类 -
isSync: boolean
是否是同步加载 在bootstrapModule
的时候是false
,异步加载
_loadModules
做了什么?
- 首先通过
this._metadataResolver.getNgModuleMetadata
获取到之前makeDecorator
在模块类上创建的 静态属性__annotations__
并编译模块的元数据 - 调用
this._filterJitIdentifiers
递归过滤掉 AOT 模块 - 调用
this._metadataResolver.loadDirectiveMetadata(moduleMeta.type.reference, ref, isSync)
异步加载全部指令组件和和管道的元数据 - 全部并行
Promise
并返回异步编译的结果 - 最后所有被导入
AppModule
关联的模块的元数据都已经加载进了缓存中,包括了 从AppModule
开始除了懒加载模块之外的的整个模块树,树上的所有指令,组件和管道,以及所有的服务 。
接下来继续看 _compileModuleAndComponents
在加载完模块之后,调用了 this._compileComponents
编译组件:
angular/packages/compiler/src/jit/compiler.ts
export class JitCompiler { // 注释:做了三件事: // 1. 加载模块 `this._loadModules` // 2. 编译入口组件 `this._compileComponents` // 3. 编译模块 `this._compileModule` private _compileModuleAndComponents(moduleType: Type, isSync: boolean): SyncAsync<object> { // 注释:其实调用的是这步,编译主模块和组件 return SyncAsync.then(this._loadModules(moduleType, isSync), () => { // 注释:先加载模块 this._compileComponents(moduleType, null); // 注释:异步有结果之后的回调函数,编译主模块上的所有入口组件 return this._compileModule(moduleType); // 注释:返回编译后的模块工厂 }); } } 复制代码
_compileComponents编译组件
_compileComponents
方法用来编译根模块组件的模板:
angular/packages/compiler/src/jit/compiler.ts
export class JitCompiler { // 注释:编译主模块上的所有组件 // 主要目的:拿到被声明的组件的模板、入口组件的模板,最终拿到了所有涉及的模板,放在 templates 中 _compileComponents(mainModule: Type, allComponentFactories: object[]|null) { // 注释:获取主模块 const ngModule = this._metadataResolver.getNgModuleMetadata(mainModule) !; const moduleByJitDirective = new Map<any, CompileNgModuleMetadata>(); const templates = new Set<CompiledTemplate>(); // 注释:过滤AOT模块 const transJitModules = this._filterJitIdentifiers(ngModule.transitiveModule.modules); // 注释:编译各个模块的模板,(localMod 是模块的class) transJitModules.forEach((localMod) => { const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod) !; // 注释:指令和组件都是 declaredDirectives (在angular里 @Component组件 继承了 指令@Directive) this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach((dirRef) => { moduleByJitDirective.set(dirRef, localModuleMeta); const dirMeta = this._metadataResolver.getDirectiveMetadata(dirRef); // 注释:只编译组件 // 注释:拿到所有的模板,并放在 templates:Set 中 if (dirMeta.isComponent) { templates.add(this._createCompiledTemplate(dirMeta, localModuleMeta)); if (allComponentFactories) { const template = this._createCompiledHostTemplate(dirMeta.type.reference, localModuleMeta); templates.add(template); allComponentFactories.push(dirMeta.componentFactory as object); } } }); }); // 注释:编译入口组件的模板 transJitModules.forEach((localMod) => { const localModuleMeta = this._metadataResolver.getNgModuleMetadata(localMod) !; this._filterJitIdentifiers(localModuleMeta.declaredDirectives).forEach((dirRef) => { const dirMeta = this._metadataResolver.getDirectiveMetadata(dirRef); if (dirMeta.isComponent) { dirMeta.entryComponents.forEach((entryComponentType) => { const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType) !; templates.add( this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta)); }); } }); localModuleMeta.entryComponents.forEach((entryComponentType) => { if (!this.hasAotSummary(entryComponentType.componentType)) { const moduleMeta = moduleByJitDirective.get(entryComponentType.componentType) !; templates.add( this._createCompiledHostTemplate(entryComponentType.componentType, moduleMeta)); } }); }); // 注释:执行 _compileTemplate 编译模板 templates.forEach((template) => this._compileTemplate(template)); } } 复制代码
在这里主要做了下面这几件事:
this._metadataResolver.getNgModuleMetadata this._filterJitIdentifiers declarations entryComponents
至于如何编译的模板,之后讲组件的时候再说吧。
_compileComponents
的 目的是拿到被声明的组件的模板、入口组件的模板,最终拿到了所有涉及的模板
_compileModule编译模块
angular/packages/compiler/src/jit/compiler.ts
export class JitCompiler { ... // 注释:angular 会用 Map 缓存模块工厂,并且在需要返回编译的模块工厂时,优先去缓存中寻找已经被编译过的模块工厂 private _compileModule(moduleType: Type): object { // 注释:从缓存拿到模块工厂 let ngModuleFactory = this._compiledNgModuleCache.get(moduleType) !; // 注释:读取缓存 if (!ngModuleFactory) { // 注释:读取模块的元数据 const moduleMeta = this._metadataResolver.getNgModuleMetadata(moduleType) !; // 注释:调用实例化 JITCompiler 时候传入方法,创建额外的模块服务供应商 (在 CompilerImpl 传入) // Always provide a bound Compiler const extraProviders = this.getExtraNgModuleProviders(moduleMeta.type.reference); // 注释:创建输出上下 const outputCtx = createOutputContext(); // 注释:构建编译结果:是一个对象,只有 ngModuleFactoryVar 这么一个属性:ngModuleFactoryVar: "AppModuleNgFactory",内部通过构建服务供应商和模块的AST,很复杂 const compileResult = this._ngModuleCompiler.compile(outputCtx, moduleMeta, extraProviders); console.log(77777, moduleType, compileResult); // 注释:动态创建出一个模块的工厂方法 ngModuleFactory = this._interpretOrJit( ngModuleJitUrl(moduleMeta), outputCtx.statements)[compileResult.ngModuleFactoryVar]; this._compiledNgModuleCache.set(moduleMeta.type.reference, ngModuleFactory); } return ngModuleFactory; } ... } 复制代码
这里也很简单:
- 先从从缓存拿到模块工厂函数
- 如果不存在工厂函数,则开始创建
- 读取模块的元数据
- 调用实例化
JITCompiler
时候传入方法,创建 额外的模块服务供应商 (在CompilerImpl
传入) - 创建输出上下
- 构建编译结果:是一个对象, 只有
ngModuleFactoryVar
这么一个属性,估计是把编译结果放缓存了 :ngModuleFactoryVar: "AppModuleNgFactory"
- 动态创建出一个模块的工厂方法并返回
NgModuleCompiler模块编译器
模块编译器这里比较复杂:
angular/packages/compiler/src/ng_module_compiler.ts
export class NgModuleCompiler { constructor(private reflector: CompileReflector) {} compile( ctx: OutputContext, ngModuleMeta: CompileNgModuleMetadata, extraProviders: CompileProviderMetadata[]): NgModuleCompileResult { // 注释:生成一个关于模块类及文件位置的对象 const sourceSpan = typeSourceSpan('NgModule', ngModuleMeta.type); // 注释:获得入口组件的工厂函数,默认就有 <ng-component/> 和 <app-root/> const entryComponentFactories = ngModuleMeta.transitiveModule.entryComponents; const bootstrapComponents = ngModuleMeta.bootstrapComponents; // 注释:分析模块及模块引入的模块的服务供应商 const providerParser = new NgModuleProviderAnalyzer(this.reflector, ngModuleMeta, extraProviders, sourceSpan); // 注释:这块是AST了,生成了模块中所有服务供应商的函数 AST const providerDefs = [componentFactoryResolverProviderDef( this.reflector, ctx, NodeFlags.None, entryComponentFactories)] .concat(providerParser.parse().map((provider) => providerDef(ctx, provider))) .map(({providerExpr, depsExpr, flags, tokenExpr}) => { return o.importExpr(Identifiers.moduleProviderDef).callFn([ o.literal(flags), tokenExpr, providerExpr, depsExpr ]); }); // 注释:这块是AST了,生成了模块的 AST const ngModuleDef = o.importExpr(Identifiers.moduleDef).callFn([o.literalArr(providerDefs)]); const ngModuleDefFactory = o.fn( [new o.FnParam(LOG_VAR.name !)], [new o.ReturnStatement(ngModuleDef)], o.INFERRED_TYPE); // 注释:创建一个字符串 const ngModuleFactoryVar = `${identifierName(ngModuleMeta.type)}NgFactory`; // 注释:保存在上下文中声明中 this._createNgModuleFactory( ctx, ngModuleMeta.type.reference, o.importExpr(Identifiers.createModuleFactory).callFn([ ctx.importExpr(ngModuleMeta.type.reference), o.literalArr(bootstrapComponents.map(id => ctx.importExpr(id.reference))), ngModuleDefFactory ])); if (ngModuleMeta.id) { const id = typeof ngModuleMeta.id === 'string' ? o.literal(ngModuleMeta.id) : ctx.importExpr(ngModuleMeta.id); const registerFactoryStmt = o.importExpr(Identifiers.RegisterModuleFactoryFn) .callFn([id, o.variable(ngModuleFactoryVar)]) .toStmt(); // 注释:保存在上下文中 ctx.statements.push(registerFactoryStmt); } // 注释:返回编译结果 return new NgModuleCompileResult(ngModuleFactoryVar); } ... } 复制代码
这里做了下面几件事情:
- 生成一个关于模块类及文件位置的对象
- 获得入口组件的工厂函数,默认就有
<ng-component/>
和<app-root/>
- 分析 模块及模块引入的模块的服务供应商(provide) ,并 生成对应的函数 AST
- 生成模块的 AST
- 最后通过把编译结果保存在上下文中返回一个作为 token 的对象
其实我没太看懂为什么要转换为 AST,这里面留几个坑
总结
总结下 @NgModule
大概发生了什么
- 在初始化的时候,通过
makeDecorator
生成@NgModule
注解 -
@NgModule
通过传入的参数和反射,生成注解附加在模块类的静态属性__annotations__
并提供给JitCompiler
编译器使用 - 当
bootstrapModule
被调用时候,在 JIT 模式下 创建了代理JitCompiler
去实现真正的编译 -
JitCompiler
编译模块调用了compileModuleAsync
并 返回模块工厂 ,并且只做了三件事:- 加载模块
this._loadModules
- 编译组件
this._compileComponents
- 编译模块
this._compileModule
- 加载模块
以上所述就是小编给大家介绍的《试读angular源码第四章:angular模块及JIT编译模块》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 试读angular源码第二章:引导模块bootstrapModule
- 试读angular源码第一章:开场与platformBrowserDynamic
- Node.js模块系统 (创建模块与加载模块)
- 黑客基础,Metasploit模块简介,渗透攻击模块、攻击载荷模块
- 022.Python模块序列化模块(json,pickle)和math模块
- 024.Python模块OS模块
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Don't Make Me Think
Steve Krug / New Riders Press / 18 August, 2005 / $35.00
Five years and more than 100,000 copies after it was first published, it's hard to imagine anyone working in Web design who hasn't read Steve Krug's "instant classic" on Web usability, but people are ......一起来看看 《Don't Make Me Think》 这本书的介绍吧!