试读angular源码第四章:angular模块及JIT编译模块
栏目: JavaScript · 发布时间: 6年前
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[]) => anyargs就是装饰器的参数,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模块
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Mastering Regular Expressions, Second Edition
Jeffrey E F Friedl / O'Reilly Media / 2002-07-15 / USD 39.95
Regular expressions are an extremely powerful tool for manipulating text and data. They have spread like wildfire in recent years, now offered as standard features in Perl, Java, VB.NET and C# (and an......一起来看看 《Mastering Regular Expressions, Second Edition》 这本书的介绍吧!
Markdown 在线编辑器
Markdown 在线编辑器
HEX CMYK 转换工具
HEX CMYK 互转工具