基于 angular/angular 源码分析
2026-03-07 | 技术深度解读
第一部分:基础架构
第二部分:核心模块
第三部分:代码生成
第四部分:设计模式
第五部分:性能与最佳实践
Angular 编译器是 Angular 框架的核心组件,负责将模板和装饰器元数据转换为高效的运行时代码。
核心职责:
源码位置:packages/compiler/src/
┌─────────────────────────────────────────────────────────────┐
│ Angular Compiler │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Template │ │ Expression │ │ HTML │ │
│ │ Parser │→ │ Parser │← │ Parser │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ↓ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ R3 AST (Template AST) │ │
│ └──────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Component │ │ Directive │ │ Module │ │
│ │ Compiler │ │ Compiler │ │ Compiler │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ↓ ↓ ↓ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Output AST (JavaScript) │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
1. 解析阶段 (Parsing)
HTML 模板 → HTML AST → R3 Template AST
2. 分析阶段 (Analysis)
装饰器元数据 → 编译元数据
3. 编译阶段 (Compilation)
编译元数据 → 中间表示 (IR)
4. 代码生成 (Code Generation)
IR → JavaScript AST → 源代码
关键文件:
parseTemplate() - 模板解析入口compileComponentFromMetadata() - 组件编译emitTemplateFn() - 代码生成| 版本 | 编译器 | 特点 |
|---|---|---|
| Angular 2-5 | JIT (默认) | 运行时编译,启动慢 |
| Angular 4+ | AOT (可选) | 编译时编译,启动快 |
| Angular 9+ | Ivy (默认) | 新的 Render3 编译器 |
| Angular 17+ | Deferred Loading | 延迟加载编译支持 |
| Angular 18+ | Control Flow | 新控制流语法 @if @for |
Ivy 编译器 是当前主要使用的编译器,代码位于 render3/ 目录
生产环境推荐使用 AOT,开发环境可使用 JIT
| 模块 | 路径 | 职责 |
|---|---|---|
| compiler.ts | src/ | 编译器入口点 |
| template.ts | render3/view/ | 模板解析 |
| compiler.ts | render3/view/ | 组件/指令编译 |
| r3_module_compiler.ts | render3/ | 模块编译 |
| r3_ast.ts | render3/ | R3 AST 节点定义 |
| parser.ts | expression_parser/ | 表达式解析 |
| html_parser.ts | ml_parser/ | HTML 解析 |
模板解析入口函数,将 HTML 字符串转换为 R3 AST
export function parseTemplate(
template: string, // 模板内容
templateUrl: string, // 模板 URL
options: ParseTemplateOptions = {},
): ParsedTemplate {
// 1. 创建绑定解析器
const bindingParser = makeBindingParser(selectorlessEnabled);
// 2. HTML 解析
const parseResult = htmlParser.parse(template, templateUrl, {
tokenizeExpansionForms: true,
tokenizeBlocks: options.enableBlockSyntax ?? true,
tokenizeLet: options.enableLetSyntax ?? true,
});
// 3. 处理 i18n 元信息
const i18nMetaResult = i18nMetaVisitor.visitAllWithErrors(rootNodes);
// 4. 转换为 R3 AST
const {nodes, errors, styleUrls, styles, ngContentSelectors} =
htmlAstToRender3Ast(rootNodes, bindingParser);
return { preserveWhitespaces, errors, nodes, styleUrls, styles, ngContentSelectors };
}
表达式解析器,处理模板中的插值表达式和绑定表达式
export class Parser {
constructor(
private readonly _lexer: Lexer,
private readonly _supportsDirectPipeReferences = false,
) {}
// 解析事件处理器
parseAction(input: string, parseSourceSpan: ParseSourceSpan,
absoluteOffset: number): ASTWithSource
// 解析属性绑定
parseBinding(input: string, parseSourceSpan: ParseSourceSpan,
absoluteOffset: number): ASTWithSource
// 解析 Host 绑定
parseSimpleBinding(input: string, parseSourceSpan: ParseSourceSpan,
absoluteOffset: number): ASTWithSource
// 解析微语法模板绑定 (*ngFor 等)
parseTemplateBindings(templateKey: string, templateValue: string,
parseSourceSpan: ParseSourceSpan, absoluteKeyOffset: number,
absoluteValueOffset: number): TemplateBindingParseResult
// 解析插值表达式
parseInterpolation(input: string, ...): ASTWithSource | null
}
HTML 解析器,将模板字符串转换为 HTML AST
export class HtmlParser extends Parser {
constructor() {
super(getHtmlTagDefinition);
}
override parse(source: string, url: string,
options?: TokenizeOptions): ParseTreeResult {
return super.parse(source, url, options);
}
}
支持特性:
*ngIf, {{}})@if, @for, @switch)@let 语法绑定解析器,处理模板中的各种绑定语法
export class BindingParser {
constructor(
private _exprParser: Parser,
private _schemaRegistry: ElementSchemaRegistry,
private _errors: ParseError[]
) {}
// 创建 Host 属性绑定
createBoundHostProperties(
properties: {[key: string]: string},
sourceSpan: ParseSourceSpan
): BoundElementProperty[]
// 创建 Host 事件绑定
createDirectiveHostEventAsts(
listeners: {[key: string]: string},
sourceSpan: ParseSourceSpan
): ParsedEvent[]
// 创建元素属性绑定
createBoundElementProperty(
elementName: string, attribute: AttrAst,
boundAttrs: BoundElementPropertyAst[]
): BoundElementProperty
}
// 工厂函数
export function makeBindingParser(selectorlessEnabled = false): BindingParser {
return new BindingParser(
new Parser(new Lexer(), selectorlessEnabled),
elementRegistry,
[]
);
}
Render3 模板 AST 定义,表示解析后的模板结构
// 节点接口
export interface Node {
sourceSpan: ParseSourceSpan;
visit<Result>(visitor: Visitor<Result>): Result;
}
// 核心节点类型
export class Element implements Node { ... } // HTML 元素
export class Template implements Node { ... } // ng-template
export class Text implements Node { ... } // 文本节点
export class BoundText implements Node { ... } // 绑定文本 {{expr}}
export class BoundAttribute implements Node { ... } // [prop]="expr"
export class BoundEvent implements Node { ... } // (event)="handler"
export class Content implements Node { ... } // ng-content
export class Reference implements Node { ... } // #ref
export class Variable implements Node { ... } // let-var
export class Component implements Node { ... } // 组件节点
export class Directive implements Node { ... } // 指令节点
组件编译核心函数,将组件元数据编译为运行时代码
export function compileComponentFromMetadata(
meta: R3ComponentMetadata<R3TemplateDependency>,
constantPool: ConstantPool,
bindingParser: BindingParser,
): R3CompiledExpression {
// 1. 基础指令字段
const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
// 2. 添加 Features
addFeatures(definitionMap, meta);
// 3. 编译模板
const tpl = ingestComponent(meta.name, meta.template.nodes, ...);
transform(tpl, CompilationJobKind.Tmpl);
const templateFn = emitTemplateFn(tpl, constantPool);
// 4. 设置组件定义
definitionMap.set('decls', o.literal(tpl.root.decls));
definitionMap.set('vars', o.literal(tpl.root.vars));
definitionMap.set('template', templateFn);
// 5. 生成代码
const expression = o.importExpr(R3.defineComponent)
.callFn([definitionMap.toLiteralMap()]);
return {expression, type, statements: []};
}
指令编译函数,将指令元数据编译为运行时代码
export function compileDirectiveFromMetadata(
meta: R3DirectiveMetadata,
constantPool: ConstantPool,
bindingParser: BindingParser,
): R3CompiledExpression {
// 1. 基础字段
const definitionMap = baseDirectiveFields(meta, constantPool, bindingParser);
// 2. 添加 Features
addFeatures(definitionMap, meta);
// 3. 生成指令定义代码
const expression = o.importExpr(R3.defineDirective)
.callFn([definitionMap.toLiteralMap()], undefined, true);
// 4. 创建类型声明
const type = createDirectiveType(meta);
return {expression, type, statements: []};
}
baseDirectiveFields 生成:
type - 指令类型selectors - 选择器inputs - 输入属性outputs - 输出事件hostBindings - Host 绑定函数模块编译函数,生成 NgModule 定义
export function compileNgModule(meta: R3NgModuleMetadata): R3CompiledExpression {
const definitionMap = new DefinitionMap<R3NgModuleDefMap>();
// 1. 设置模块类型
definitionMap.set('type', meta.type.value);
// 2. 设置 bootstrap 组件
if (meta.bootstrap.length > 0) {
definitionMap.set('bootstrap', refsToArray(meta.bootstrap, ...));
}
// 3. 设置作用域 (declarations, imports, exports)
if (meta.selectorScopeMode === R3SelectorScopeMode.Inline) {
definitionMap.set('declarations', refsToArray(meta.declarations, ...));
definitionMap.set('imports', refsToArray(meta.imports, ...));
definitionMap.set('exports', refsToArray(meta.exports, ...));
}
// 4. 生成模块定义
const expression = o.importExpr(R3.defineNgModule)
.callFn([definitionMap.toLiteralMap()]);
return {expression, type, statements};
}
Pipe 编译函数,生成 Pipe 定义
export function compilePipeFromMetadata(
meta: R3PipeMetadata
): R3CompiledExpression {
const definitionMap = new DefinitionMap();
definitionMap.set('type', meta.type.value);
definitionMap.set('name', o.literal(meta.name)); // pipe 名称
definitionMap.set('pure', o.literal(meta.isPure)); // 是否纯 pipe
const expression = o.importExpr(R3.definePipe)
.callFn([definitionMap.toLiteralMap()]);
return {expression, type, statements: []};
}
纯 Pipe vs 非纯 Pipe:
解析 Host 绑定,处理 @HostBinding 和 @HostListener
export interface ParsedHostBindings {
attributes: {[key: string]: o.Expression}; // 静态属性
listeners: {[key: string]: string}; // 事件监听器
properties: {[key: string]: string}; // 属性绑定
specialAttributes: {styleAttr?: string; classAttr?: string};
}
export function parseHostBindings(host: {
[key: string]: string | o.Expression;
}): ParsedHostBindings {
const attributes: {[key: string]: o.Expression} = {};
const listeners: {[key: string]: string} = {};
const properties: {[key: string]: string} = {};
for (const key of Object.keys(host)) {
const matches = key.match(HOST_REG_EXP); // [prop] 或 (event)
if (matches === null) {
// 静态属性: class, style, 或普通属性
attributes[key] = typeof value === 'string' ? o.literal(value) : value;
} else if (matches[HostBindingGroup.Binding] != null) {
// 属性绑定: [prop]
properties[matches[HostBindingGroup.Binding]] = value;
} else if (matches[HostBindingGroup.Event] != null) {
// 事件监听: (event)
listeners[matches[HostBindingGroup.Event]] = value;
}
}
return {attributes, listeners, properties, specialAttributes};
}
模板摄取函数,将 R3 AST 转换为中间表示 (IR)
// 从 template/pipeline/src/ingest.ts
export function ingestComponent(
name: string,
nodes: t.Node[],
constantPool: ConstantPool,
compilationMode: TemplateCompilationMode,
relativeContextFilePath: string,
i18nUseExternalIds: boolean,
defer: DeferBlockEmitMode,
allDeferrableDepsFn: o.ReadVarExpr | null,
relativeTemplatePath: string | null,
enableTemplateSourceLocations: boolean,
): Compilation {
// 1. 创建编译作业
const job = new CompilationJob(name, compilationMode, ...);
// 2. 遍历 AST 节点,生成 IR 指令
for (const node of nodes) {
node.visit(new TemplateIngestor(job, ...));
}
// 3. 返回编译结果
return job;
}
IR 转换阶段:
ingestComponent - 摄取为 IRtransform - 优化转换emitTemplateFn - 生成代码代码生成函数,将 IR 转换为 JavaScript 代码
// 从 template/pipeline/src/emit.ts
export function emitTemplateFn(
job: Compilation,
constantPool: ConstantPool
): o.Expression {
// 1. 创建模板函数
const params = [
new o.FnParam('rf', o.NONE_TYPE), // RenderFlag
new o.FnParam('ctx', o.NONE_TYPE), // 组件上下文
];
// 2. 生成指令序列
const statements: o.Statement[] = [];
// 3. 遍历 IR 节点,生成代码
for (const ir of job.root.instructions) {
statements.push(emitInstruction(ir, constantPool));
}
// 4. 返回箭头函数
return o.arrowFn(params, statements);
}
生成的代码示例:
function MyComponent_Template(rf, ctx) {
if (rf & 1) { // 创建模式
i0.ɵɵelementStart(0, "div");
i0.ɵɵtext(1);
i0.ɵɵelementEnd();
}
if (rf & 2) { // 更新模式
i0.ɵɵadvance(1);
i0.ɵɵtextInterpolate(ctx.title);
}
}
Node (interface)
│
┌─────────┼─────────┬─────────┐
│ │ │ │
Text BoundText Element Template
│ │ │ │
│ │ ┌────┴────┐ │
│ │ │ │ │
│ │ Content Component Directive
│ │
│ ┌─────┴─────┐
│ │ │
TextAttribute BoundAttribute BoundEvent
│
├─────────┬─────────┐
│ │ │
Reference Variable Icu
│
├─────────┴─────────┐
│ │
DeferredBlock ControlFlowBlock
│ │
├───┼───┐ ├───┼───┤
Placeholder Loading Error If For Switch
表示 HTML 元素的 AST 节点
export class Element implements Node {
constructor(
public name: string, // 标签名
public attributes: TextAttribute[], // 静态属性
public inputs: BoundAttribute[], // 输入绑定
public outputs: BoundEvent[], // 输出绑定
public directives: Directive[], // 应用的指令
public children: Node[], // 子节点
public references: Reference[], // 模板引用
public isSelfClosing: boolean, // 自闭合标签
public sourceSpan: ParseSourceSpan,
public startSourceSpan: ParseSourceSpan,
public endSourceSpan: ParseSourceSpan | null,
readonly isVoid: boolean, // void 元素
public i18n?: I18nMeta,
) {}
visit<Result>(visitor: Visitor<Result>): Result {
return visitor.visitElement(this);
}
}
表示 ng-template 或结构指令的 AST 节点
export class Template implements Node {
constructor(
public tagName: string | null, // 容器标签名
public attributes: TextAttribute[],
public inputs: BoundAttribute[],
public outputs: BoundEvent[],
public directives: Directive[],
public templateAttrs: (BoundAttribute | TextAttribute)[], // 模板属性
public children: Node[], // 模板内容
public references: Reference[],
public variables: Variable[], // 模板变量 (let-*)
public isSelfClosing: boolean,
public sourceSpan: ParseSourceSpan,
public startSourceSpan: ParseSourceSpan,
public endSourceSpan: ParseSourceSpan | null,
public i18n?: I18nMeta,
) {}
visit<Result>(visitor: Visitor<Result>): Result {
return visitor.visitTemplate(this);
}
}
表示属性绑定的 AST 节点
export class BoundAttribute implements Node {
constructor(
public name: string, // 属性名
public type: BindingType, // 绑定类型
public securityContext: SecurityContext,
public value: AST, // 绑定表达式 AST
public unit: string | null, // 单位 (如 'px')
public sourceSpan: ParseSourceSpan,
readonly keySpan: ParseSourceSpan,
public valueSpan: ParseSourceSpan | undefined,
public i18n: I18nMeta | undefined,
) {}
static fromBoundElementProperty(
prop: BoundElementProperty,
i18n?: I18nMeta
): BoundAttribute
visit<Result>(visitor: Visitor<Result>): Result {
return visitor.visitBoundAttribute(this);
}
}
绑定类型 (BindingType):
Property - [property]Attribute - [attr.name]Class - [class.name]Style - [style.name]Animation - [@animation]表示事件绑定的 AST 节点
export class BoundEvent implements Node {
constructor(
public name: string, // 事件名
public type: ParsedEventType, // 事件类型
public handler: AST, // 处理器表达式
public target: string | null, // 目标 (window, document 等)
public phase: string | null, // 事件阶段 (capture 等)
public sourceSpan: ParseSourceSpan,
public handlerSpan: ParseSourceSpan,
readonly keySpan: ParseSourceSpan,
) {}
static fromParsedEvent(event: ParsedEvent): BoundEvent
visit<Result>(visitor: Visitor<Result>): Result {
return visitor.visitBoundEvent(this);
}
}
事件类型:
Regular - (click)="handler()"LegacyAnimation - (@anim.done)Angular 17+ 新增的延迟加载语法
export class DeferredBlock extends BlockNode implements Node {
readonly triggers: Readonly<DeferredBlockTriggers>;
readonly prefetchTriggers: Readonly<DeferredBlockTriggers>;
readonly hydrateTriggers: Readonly<DeferredBlockTriggers>;
constructor(
public children: Node[],
triggers: DeferredBlockTriggers,
prefetchTriggers: DeferredBlockTriggers,
hydrateTriggers: DeferredBlockTriggers,
public placeholder: DeferredBlockPlaceholder | null,
public loading: DeferredBlockLoading | null,
public error: DeferredBlockError | null,
...
) {}
}
// 触发器类型
export interface DeferredBlockTriggers {
when?: BoundDeferredTrigger; // @defer (when condition)
idle?: IdleDeferredTrigger; // @defer (on idle)
immediate?: ImmediateDeferredTrigger;
hover?: HoverDeferredTrigger;
timer?: TimerDeferredTrigger; // @defer (on timer(500ms))
interaction?: InteractionDeferredTrigger;
viewport?: ViewportDeferredTrigger;
never?: NeverDeferredTrigger;
}
Angular 18+ 新的控制流语法
// @if 块
export class IfBlock extends BlockNode implements Node {
constructor(
public branches: IfBlockBranch[],
...
) {}
}
export class IfBlockBranch extends BlockNode {
constructor(
public expression: AST | null, // 条件表达式
public children: Node[],
public expressionAlias: Variable | null, // as alias
...
) {}
}
// @for 块
export class ForLoopBlock extends BlockNode implements Node {
constructor(
public item: Variable, // let item
public expression: ASTWithSource, // of items
public trackBy: ASTWithSource, // track by
public contextVariables: Variable[], // $index, $odd 等
public children: Node[],
public empty: ForLoopBlockEmpty | null, // @empty
...
) {}
}
// @switch 块
export class SwitchBlock extends BlockNode implements Node {
constructor(
public expression: AST,
public groups: SwitchBlockCaseGroup[],
public exhaustiveCheck: SwitchExhaustiveCheck | null,
...
) {}
}
常量池,用于优化重复表达式的生成
export class ConstantPool {
// 存储常量定义语句
statements: o.Statement[] = [];
// 获取或创建常量字面量
getConstLiteral(
literal: o.LiteralExpr,
forceShared: boolean
): o.Expression {
// 检查是否已存在相同的常量
// 如果存在则返回引用,否则创建新常量
}
// 插入常量定义
insertWhenSharing(
literal: o.Expression
): o.Expression
}
优化效果:
JavaScript 代码生成的抽象语法树
// 表达式类型
export class LiteralExpr { ... } // 字面量
export class LiteralArrayExpr { ... } // 数组
export class LiteralMapExpr { ... } // 对象
export class ExternalExpr { ... } // 外部引用
export class InvokeFunctionExpr { ... } // 函数调用
export class ReadPropExpr { ... } // 属性访问
export class ArrowFunctionExpr { ... } // 箭头函数
export class DynamicImportExpr { ... } // 动态 import
// 语句类型
export class DeclareVarStmt { ... } // 变量声明
export class DeclareFunctionStmt { ... }// 函数声明
export class IfStmt { ... } // if 语句
export class ReturnStatement { ... } // return 语句
export class ExpressionStatement { ... }// 表达式语句
// 工厂函数
export function literal(value: any): LiteralExpr
export function literalArr(values: Expression[]): LiteralArrayExpr
export function literalMap(entries: {...}[]): LiteralMapExpr
export function importExpr(id: Identifiers): ExternalExpr
用于构建组件/指令定义对象
export class DefinitionMap<T = {[key: string]: o.Expression}> {
values: T;
set<K extends keyof T>(key: K, value: T[K]): void {
this.values[key] = value;
}
toLiteralMap(): o.LiteralMapExpr {
const entries = Object.keys(this.values).map(key => ({
key,
value: this.values[key],
quoted: false,
}));
return o.literalMap(entries);
}
}
// 使用示例
const definitionMap = new DefinitionMap();
definitionMap.set('type', meta.type.value);
definitionMap.set('selectors', asLiteral(selectors));
definitionMap.set('inputs', conditionallyCreateDirectiveBindingLiteral(meta.inputs));
const expression = o.importExpr(R3.defineComponent)
.callFn([definitionMap.toLiteralMap()]);
实现视图封装的样式作用域隔离
const COMPONENT_VARIABLE = '%COMP%';
const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
function compileStyles(
styles: string[],
selector: string,
hostSelector: string
): string[] {
const shadowCss = new ShadowCss();
return styles.map(style => {
return shadowCss.shimCssText(style, selector, hostSelector);
});
}
export function encapsulateStyle(
style: string,
componentIdentifier?: string
): string {
const shadowCss = new ShadowCss();
const selector = componentIdentifier
? CONTENT_ATTR.replace(COMPONENT_VARIABLE, componentIdentifier)
: CONTENT_ATTR;
return shadowCss.shimCssText(style, selector, hostSelector);
}
封装效果: .title → .title[_ngcontent-abc]
遍历和处理 AST 节点的核心模式
export interface Visitor<Result = any> {
visit?(node: Node): Result; // 通用访问
visitElement(element: Element): Result;
visitTemplate(template: Template): Result;
visitContent(content: Content): Result;
visitText(text: Text): Result;
visitBoundText(text: BoundText): Result;
visitBoundAttribute(attribute: BoundAttribute): Result;
visitBoundEvent(attribute: BoundEvent): Result;
// ... 更多 visit 方法
}
// 递归访问者基类
export class RecursiveVisitor implements Visitor<void> {
visitElement(element: Element): void {
visitAll(this, element.attributes);
visitAll(this, element.inputs);
visitAll(this, element.outputs);
visitAll(this, element.children);
}
// ... 其他方法
}
// 遍历所有节点
export function visitAll<Result>(
visitor: Visitor<Result>,
nodes: Node[]
): Result[]
AST 节点的树形结构设计
// 所有节点实现统一接口
export interface Node {
sourceSpan: ParseSourceSpan;
visit<Result>(visitor: Visitor<Result>): Result;
}
// Element 节点包含子节点
export class Element implements Node {
constructor(
public name: string,
public attributes: TextAttribute[], // 子节点
public inputs: BoundAttribute[], // 子节点
public outputs: BoundEvent[], // 子节点
public children: Node[], // 递归包含更多 Node
...
) {}
}
// Template 节点也包含子节点
export class Template implements Node {
constructor(
public children: Node[], // 递归结构
public variables: Variable[],
...
) {}
}
创建复杂对象的工厂函数
// BindingParser 工厂
export function makeBindingParser(
selectorlessEnabled = false
): BindingParser {
return new BindingParser(
new Parser(new Lexer(), selectorlessEnabled),
new DomElementSchemaRegistry(),
[]
);
}
// BoundAttribute 工厂
export class BoundAttribute {
static fromBoundElementProperty(
prop: BoundElementProperty,
i18n?: I18nMeta
): BoundAttribute {
return new BoundAttribute(
prop.name, prop.type, prop.securityContext,
prop.value, prop.unit, prop.sourceSpan,
prop.keySpan, prop.valueSpan, i18n
);
}
}
// BoundEvent 工厂
export class BoundEvent {
static fromParsedEvent(event: ParsedEvent): BoundEvent {
const target = event.type === ParsedEventType.Regular
? event.targetOrPhase : null;
return new BoundEvent(event.name, event.type, ...);
}
}
┌─────────────────────────────────────────────────────────────┐
│ 模板字符串 │
│ "<div *ngIf='show' [class]='cls'>{{title}}</div>" │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ HtmlParser.parse() │
│ 解析 HTML 标签、属性、文本 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ HTML AST (ml_parser/ast) │
│ Element, Attribute, Text 节点 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ htmlAstToRender3Ast() │
│ 解析绑定、指令、控制流 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ R3 Template AST │
│ Element, BoundAttribute, BoundEvent, Template 等 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ @Component({...}) 元数据 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ compileComponentFromMetadata() │
│ 1. baseDirectiveFields() - 基础字段 │
│ 2. addFeatures() - 添加 Features │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ ingestComponent() │
│ 将模板 AST 转换为 IR (中间表示) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ transform() │
│ 优化和转换 IR │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ emitTemplateFn() │
│ 生成模板函数代码 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ ɵɵdefineComponent({...}) │
│ 运行时组件定义 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ @NgModule({...}) 元数据 │
│ declarations, imports, exports, bootstrap │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ compileNgModule() │
│ 根据 selectorScopeMode 选择编译策略 │
└─────────────────────────────────────────────────────────────┘
↓
┌───────────────────┼───────────────────┐
↓ ↓ ↓
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Inline │ │ SideEffect │ │ Omit │
│ 内联到定义 │ │ 侧边函数 │ │ 不生成 │
└──────────────┘ └──────────────┘ └──────────────┘
↓ ↓
└───────────────────┼───────────────────┐
↓
┌─────────────────────────────────────────────────────────────┐
│ ɵɵdefineNgModule({...}) │
│ 运行时模块定义 │
└─────────────────────────────────────────────────────────────┘
中间表示的优化和转换管道
// template/pipeline/src/compilation.ts
export const enum CompilationJobKind {
Tmpl, // 模板编译
Host, // Host 绑定编译
}
// 摄取阶段
const tpl = ingestComponent(
meta.name,
meta.template.nodes,
constantPool,
compilationMode,
...
);
// 转换阶段
transform(tpl, CompilationJobKind.Tmpl);
// 发射阶段
const templateFn = emitTemplateFn(tpl, constantPool);
转换优化:
// RenderFlag 位标记
const enum RenderFlags {
Create = 1, // 创建模式
Update = 2, // 更新模式
}
if (rf & RenderFlags.Create) {
// 创建 DOM 结构
}
if (rf & RenderFlags.Update) {
// 更新绑定值
}
编译器生成的代码支持 Tree Shaking
// R3SelectorScopeMode 控制声明方式
export enum R3SelectorScopeMode {
Inline, // 内联 - 不利于 Tree Shaking
SideEffect, // 侧边函数 - 支持 Tree Shaking
Omit, // 省略 - 完全不生成
}
// 侧边函数示例 (JIT 模式)
(function() {
ngJitMode && ɵɵsetNgModuleScope(MyModule, {
declarations: [MyComponent],
imports: [CommonModule],
});
})();
// 生产环境 ngJitMode = false,整个函数被删除
Tree Shaking 原理:未使用的声明代码被侧边函数包裹,在 AOT 编译时可以被移除
只重新编译修改过的文件
// Angular CLI 增量编译策略
1. 文件变更检测
- 监听文件系统变化
- 计算文件哈希
2. 依赖图分析
- 模块依赖
- 组件依赖
- 模板依赖
3. 影响范围计算
- 修改组件 → 重新编译组件
- 修改服务 → 检查注入者
- 修改模板 → 重新编译模板
4. 增量编译
- 只编译受影响的文件
- 复用之前的编译结果
Angular CLI 使用 webpack 或 esbuild 实现增量编译
// ✅ 使用 trackBy
@for (item of items; track item.id) {
<div>{{item.name}}</div>
}
// ✅ 使用 @defer 延迟加载
@defer (on viewport) {
<heavy-component />
}
// ✅ 使用 standalone 组件
@Component({
selector: 'app-hero',
standalone: true,
imports: [CommonModule],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `...`
})
export class HeroComponent {}
// ✅ 使用 Signal 输入
export class HeroComponent {
hero = input.required<Hero>();
// 自动派生
heroName = computed(() => this.hero().name);
}
// ✅ 使用 Host 绑定
@HostBinding('class.active')
isActive = false;
@HostListener('click')
onClick() {
this.isActive = !this.isActive;
}
| 反模式 | 问题 | 解决方案 |
|---|---|---|
| 默认变更检测 | 性能差 | 使用 OnPush |
| 非纯 Pipe | 频繁执行 | 使用纯 Pipe 或 memoize |
| 大模板文件 | 编译慢 | 拆分为小组件 |
| 循环中的复杂计算 | 性能差 | 预计算或 memoize |
| 深度对象绑定 | 变更检测慢 | 扁平化数据 |
// 1. 查看编译后的代码
ng build --source-map
// 2. 启用编译器调试模式
import { enableDebugTools } from '@angular/platform-browser';
enableDebugTools();
// 3. 查看 AOT 编译产物
ngc --help
ngc -p tsconfig.aot.json
// 4. 分析编译性能
ng build --stats-json
npx webpack-bundle-analyzer dist/stats.json
// 5. 模板类型检查
// tsconfig.json
{
"angularCompilerOptions": {
"strictTemplates": true,
"fullTemplateTypeCheck": true
}
}
// tsconfig.json
{
"angularCompilerOptions": {
// 严格模式
"strictTemplates": true,
"strictInputTypes": true,
"strictNullInputTypes": true,
// 编译模式
"fullTemplateTypeCheck": true,
"enableI18nLegacyMessageIdFormat": false,
// 性能选项
"compilationMode": "full", // 'partial' | 'full'
"preserveWhitespaces": false,
// 高级选项
"annotationsAs": "static fields",
"annotateForClosureCompiler": true,
"skipTemplateCodegen": false,
"enableResourceInlining": false
}
}
社区资源
packages/compiler/src/
├── compiler.ts # 入口文件
├── core.ts # 核心类型
├── config.ts # 配置选项
├── constant_pool.ts # 常量池
│
├── render3/ # Ivy 编译器
│ ├── r3_ast.ts # R3 AST 节点
│ ├── r3_module_compiler.ts
│ ├── r3_pipe_compiler.ts
│ ├── r3_factory.ts
│ └── view/
│ ├── compiler.ts # 组件/指令编译
│ ├── template.ts # 模板解析
│ └── util.ts
│
├── expression_parser/ # 表达式解析
│ ├── lexer.ts
│ ├── parser.ts
│ └── ast.ts
│
├── ml_parser/ # 标记语言解析
│ ├── html_parser.ts
│ ├── lexer.ts
│ └── ast.ts
│
├── template_parser/ # 模板绑定解析
│ └── binding_parser.ts
│
├── output/ # 代码生成
│ ├── output_ast.ts
│ └── abstract_emitter.ts
│
└── i18n/ # 国际化
└── i18n_ast.ts
| 版本 | 年份 | 编译器特性 |
|---|---|---|
| Angular 2 | 2016 | JIT 编译器 |
| Angular 4 | 2017 | AOT 编译器 (可选) |
| Angular 6 | 2018 | Ivy 预览 |
| Angular 9 | 2020 | Ivy 默认启用 |
| Angular 14 | 2022 | Standalone 组件 |
| Angular 17 | 2023 | Deferred Loading 语法 |
| Angular 18 | 2024 | 新控制流语法稳定 |
Angular 编译器核心要点:
关键 API:
parseTemplate() - 模板解析入口compileComponentFromMetadata() - 组件编译compileNgModule() - 模块编译emitTemplateFn() - 代码生成源码:github.com/angular/angular/tree/main/packages/compiler
访问地址:
https://atcfu.com/ai-articles/angular-compiler/
2026-03-07 | 基于 angular/angular 源码分析