Angular
Published on: 28 November 2025
Tags: #javascript
The Problem
The core problem is the exponential complexity of maintaining state-to-view synchronization and architectural consistency in massive applications, where manual (imperative) DOM updates inevitably lead to fragile, unscalable codebases.
The Ivy Engine: LView & TView
classDiagram
note "Level 2: Ivy Internal Structures (Deep)"
%% The Static Blueprint
class TView {
+firstChild: TNode
+template: TemplateFn
+data: Array
+bindingStartIndex: number
<>
}
%% The Static DOM Definition
class TNode {
+index: number
+tagName: string
+flags: TNodeFlags
+next: TNode
<>
}
%% The Runtime Instance
class LView {
+Array structure
----------------
[0]: HOST (RNode)
[1]: TVIEW (Blueprint)
[9]: INJECTOR (LInjector)
[20]: HEADER_OFFSET
[20+]: RNodes & Vars
}
%% The actual Native Node
class RNode {
<>
}
%% Relationships
TView "1" --* "many" TNode : linked list (firstChild)
TView "1" -- "many" LView : schemas
LView --> TView : [1]
LView --> RNode : [20+]
%% The Explicit Mapping
TNode .. RNode : LView[ TNode.index ] === RNode
Compilation: JIT vs AOT & The Instruction Set
flowchart LR
subgraph Source["Source Code"]
direction TB
HTML["template: '{{val}}'"]
TS["@Component(...) class App { val = 0; }"]
end
subgraph Compiler["Ivy Compiler (ngtsc)"]
direction TB
Parse[Parse Template]
Check[Type Checking & Analysis]
Gen[Generate Instructions]
Parse --> Check --> Gen
end
subgraph Runtime["Runtime Code (AOT)"]
direction TB
Def["static ɵcmp = defineComponent(...)"]
Code["template: function(rf, ctx) {
// Phase 1: Creation (Runs ONCE)
if (rf & 1) {
ɵɵelementStart(0,'div');
ɵɵtext(1);
ɵɵelementEnd();
}
// Phase 2: Update (Runs on CD)
if (rf & 2) {
ɵɵadvance(1);
ɵɵtextInterpolate(ctx.val);
}
}"]
end
Source --> Compiler --> Runtime
style Code text-align:left,font-family:monospace
Change Detection: Zone.js vs. Signals
graph TD
subgraph Zones["Zone.js (ChangeDetectionStrategy.Default)"]
direction TB
Event(Click Event) -->|Patched API| Zone[NgZone.onMicrotaskEmpty]
Zone -->|Triggers| Tick[AppRef.tick]
Tick -->|1. Check Root| Root[Root Component]
Root -->|2. Propagate Down| Child1[Child Component]
Root -->|2. Propagate Down| Child2[Child Component]
Child1 -->|3. Check| GrandChild1
style Tick fill:#ffccbc,stroke:#d84315
end
subgraph Signals["Signal Graph (Push/Pull System)"]
direction TB
S1[("Signal A (Producer)")]
C1[("Computed B (Consumer)")]
E1[("Template Effect (Renderer)")]
%% The Push Phase
S1 -.->|1. PUSH: Mark Dirty| C1
C1 -.->|2. PUSH: Mark Dirty| E1
%% The Pull Phase
E1 ==>|3. PULL: Read Value| C1
C1 ==>|4. PULL: Recalculate| S1
style S1 fill:#e1f5fe,stroke:#01579b
style E1 fill:#f9f,stroke:#333
end
Dependency Injection (DI) Internals
sequenceDiagram
participant C as Component
participant NI as NodeInjector (Element)
participant PI as Parent ElementInjector
participant RI as Root EnvInjector
participant PL as PlatformInjector
participant Null as NullInjector
Note over C, NI: 1. Element Injector Tree (The DOM)
C->>NI: Request Service X
alt Found in Node
NI-->>C: Return Instance
else Not Found
NI->>PI: Bubble up DOM Tree
alt Found in Parent
PI-->>C: Return Instance
else Not Found
note right of PI: End of DOM Tree.
Bridge to Environment Tree.
PI->>RI: Switch Hierarchy
Note over RI, Null: 2. Environment Injector Tree (The Module/App)
alt Found in App Root
RI-->>C: Return Instance
else Not Found
RI->>PL: Check Platform
alt Found in Platform
PL-->>C: Return Instance (e.g. DOCUMENT)
else Not Found
PL->>Null: Last Resort
Null-->>C: Throw NullInjectorError
end
end
end
end
Bootstrapping Flow
graph TD
subgraph Platform["Phase 1: Platform (Shared)"]
direction TB
P1[platformBrowserDynamic] --> P2[Create PlatformInjector]
P2 --> P3[Singleton across all apps on page]
end
subgraph App["Phase 2: Application (Per App)"]
direction TB
B1[bootstrapApplication call] --> B2[Create EnvironmentInjector]
B2 --> B3[Instantiate ApplicationRef]
B3 --> Z{Is Zone.js used?}
Z -->|Yes| Z1[Init NgZone]
Z -->|No| Z2[Init ɵChangeDetectionScheduler]
Z1 --> Boot[ApplicationRef.bootstrap]
Z2 --> Boot
end
subgraph Render["Phase 3: Ivy Rendering"]
direction TB
Boot --> C1[Resolve Root ComponentFactory]
C1 --> H{Hydration Enabled?}
H -->|Yes| H1[Locate Existing DOM Nodes]
H -->|No| H2[Create New Host Element]
H1 --> LV[Create Root LView]
H2 --> LV
LV --> Tick[First Tick: AppRef.tick]
Tick --> Listeners[Run APP_BOOTSTRAP_LISTENER]
end
style Boot fill:#e1f5fe,stroke:#01579b,stroke-width:2px
style LV fill:#fff9c4,stroke:#fbc02d