Angular Rust Compiler

December 30, 2025 Β· View on GitHub

High-performance Angular AOT compiler written in Rust, providing full static compilation of Angular components and directives.

🎯 Project Status

Overall Progress: ~85% Complete
Status: βœ… Functional - Can compile Angular components to JavaScript


πŸš€ Quick Start

Prerequisites

  • Rust 1.70+
  • Cargo

Build & Run

# Build the compiler
cargo build -p angular-compiler-cli --release

# Compile an Angular project
cargo run -p angular-compiler-cli --bin ngc -- -p demo-app/tsconfig.json

Output files will be generated in demo-app/rust-output/.


βœ… What's Working

Core Compilation Features

FeatureStatusDescription
Component Compilationβœ…@Component decorator parsing and Ivy compilation
Directive Compilationβœ…@Directive support with Ι΅dir emission
Template Parsingβœ…Full HTML/Angular template parsing
Template Pipelineβœ…IR generation and optimization phases
Code Generationβœ…JavaScript emission with Ι΅cmp definitions
Inline Stylesβœ…Style extraction and scoping ([_ngcontent-%COMP%])
External Templatesβœ…templateUrl resolution
External Stylesβœ…styleUrls loading

Angular Template Syntax

SyntaxStatusExample
Text Interpolationβœ…{{ expression }}
Property Bindingβœ…[property]="value"
Event Bindingβœ…(click)="handler()" with Ι΅Ι΅listener()
Two-way Bindingβœ…[(ngModel)]="value"
@for Loopsβœ…@for (item of items; track item.id)
@if Conditionalsβœ…@if (condition) { ... }
@switchβœ…@switch (value) { @case ... }
@let Declarationsβœ…@let name = expression
*ngFor Directiveβœ…*ngFor="let item of items; index as i"
*ngIf Directiveβœ…*ngIf="condition"
ng-contentβœ…Content projection
Template Referencesβœ…#ref

Metadata Extraction

PropertyStatusDetails
selectorβœ…Component/Directive selector
inputsβœ…@Input() and input() signal
outputsβœ…@Output() and output() signal
changeDetectionβœ…ChangeDetectionStrategy.OnPush (emits as 0)
standaloneβœ…Standalone components
importsβœ…Component imports
hostDirectives⏳Pending

Signal Support

Signal TypeStatus
input()βœ…
input.required()βœ…
output()βœ…
signal()βœ…
computed()βœ…

πŸ“ Project Structure

rust-compiler/
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ compiler/                  # Core Angular compiler
β”‚   β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”‚   β”œβ”€β”€ expression_parser/ # Expression parsing
β”‚   β”‚   β”‚   β”œβ”€β”€ ml_parser/         # HTML/template parsing
β”‚   β”‚   β”‚   β”œβ”€β”€ template/          # Template pipeline
β”‚   β”‚   β”‚   β”‚   └── pipeline/      # IR & optimization phases
β”‚   β”‚   β”‚   β”œβ”€β”€ render3/           # Render3 code generation
β”‚   β”‚   β”‚   β”œβ”€β”€ output/            # AST & JavaScript emission
β”‚   β”‚   β”‚   └── shadow_css/        # CSS scoping
β”‚   β”‚   └── Cargo.toml
β”‚   β”‚
β”‚   └── compiler-cli/              # CLI interface
β”‚       β”œβ”€β”€ src/
β”‚       β”‚   β”œβ”€β”€ ngtsc/             # Angular TypeScript Compiler
β”‚       β”‚   β”‚   β”œβ”€β”€ core/          # Core compilation logic
β”‚       β”‚   β”‚   β”œβ”€β”€ metadata/      # Metadata extraction
β”‚       β”‚   β”‚   └── annotations/   # Decorator handlers
β”‚       β”‚   └── main.rs            # CLI entry point
β”‚       └── Cargo.toml
β”‚
β”œβ”€β”€ demo-app/                      # Example Angular app
β”‚   β”œβ”€β”€ src/app/
β”‚   β”‚   β”œβ”€β”€ app.ts                 # Main component
β”‚   β”‚   └── app.html               # Template
β”‚   β”œβ”€β”€ rust-output/               # Compiled output
β”‚   └── tsconfig.json
β”‚
└── Cargo.toml                     # Workspace config

οΏ½ Usage Examples

Compile a Project

cargo run -p angular-compiler-cli --bin ngc -- -p path/to/tsconfig.json

Example Input

// app.ts
@Component({
  selector: "app-root",
  templateUrl: "./app.html",
  styleUrls: ["./app.css"],
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: true,
  imports: [CommonModule],
})
export class App {
  title = input<string>("Hello");
  count = signal(0);
  items = signal([{ id: 1, name: "Item 1" }]);

  clicked = output<void>();
}
<!-- app.html -->
<h1>{{ title() }}</h1>
@for (item of items(); track item.id; let idx = $index) {
<div>{{ idx + 1 }}. {{ item.name }}</div>
}

Example Output

// app.js
import * as i0 from "@angular/core";

function App_For_1_Template(rf, ctx) {
  if (rf & 1) {
    i0.Ι΅Ι΅elementStart(0, "div");
    i0.Ι΅Ι΅text(1);
    i0.Ι΅Ι΅elementEnd();
  }
  if (rf & 2) {
    const item_r1 = ctx.$implicit;
    const $index_r2 = ctx.$index;
    i0.Ι΅Ι΅advance();
    i0.Ι΅Ι΅textInterpolate2("", $index_r2 + 1, ". ", item_r1.name, "");
  }
}

export class App {
  // ... class body
  static Ι΅cmp = i0.Ι΅Ι΅defineComponent({
    type: App,
    selectors: [["app-root"]],
    inputs: { title: [1, "title"] },
    outputs: { clicked: "clicked" },
    changeDetection: 0,
    standalone: true,
    // ...
  });
}

πŸ“ˆ Performance

MetricRust CompilerNGTSC (TypeScript)
Full Build (123 files)~2.88s~3.70s
Speedup~1.3x fasterBaseline
Memory UsageLow (Native)High (V8 Heap)

πŸ§ͺ Running Tests

# All compiler tests
cargo test -p angular-compiler

# All compiler-cli tests
cargo test -p angular-compiler-cli

# Specific test suite
cargo test -p angular-compiler ml_parser
cargo test -p angular-compiler expression_parser

πŸ› οΈ Recent Improvements

December 2024 (Latest)

Control Flow - @for Loops

FeatureStatusNotes
Basic @forβœ…@for (item of items; track item.id)
Context Variablesβœ…$index, $count, $first, $last, $even, $odd
Local Aliasesβœ…let idx = $index, first = $first
Nested @forβœ…Multiple levels with correct context
@empty Blockβœ…Fallback when collection is empty
Track By Functionβœ…track item.id or track trackFn($index, item)
Event Handlers⚠️Works but has view hierarchy issue in nested conditionals

Known Issue: @for inside @if/@else blocks may cause nextContext() to return undefined in event handlers. Investigating.

Control Flow - @if Conditionals

FeatureStatusNotes
Basic @ifβœ…@if (condition) { ... }
@else Blockβœ…@if (condition) { ... } @else { ... }
@else ifβœ…Chained conditionals
Template Chainingβœ…conditionalCreate() fluent API

NgFor Directive (*ngFor)

  • βœ… Full Template Syntax: *ngFor="let item of items; index as i; first as isFirst; last as isLast; even as isEven; odd as isOdd; trackBy: trackFn"
  • βœ… Context Variables: All loop variables ($implicit, index, count, first, last, even, odd) correctly mapped
  • βœ… Source-Span Sorting: Attributes in consts array are sorted by their source position in the template, ensuring parity with NGTSC
  • βœ… Nested Loops: Full support for nested *ngFor with correct view restoration
  • βœ… Event Handlers Inside Loops: Proper getCurrentView()/restoreView() emission for event handlers within loop bodies

NgIf Directive (*ngIf)

  • βœ… Basic Conditionals: *ngIf="condition"
  • βœ… Else Template: *ngIf="condition; else elseTemplate" with TemplateRef extraction
  • βœ… Then/Else Templates: *ngIf="condition; then thenTpl; else elseTpl"
  • βœ… As Syntax: *ngIf="user$ | async as user" with local variable binding
  • βœ… Nested NgIf: Complex nested conditionals with proper context isolation

Two-Way Binding ([(ngModel)])

  • βœ… Ι΅Ι΅twoWayListener: Proper two-way listener emission
  • βœ… Ι΅Ι΅twoWayProperty: Property binding for two-way data flow
  • βœ… Ι΅Ι΅twoWayBindingSet: Setter with fallback assignment

Optimizations & Parity

  • βœ… RestoreView Optimization: Single-usage context variables are inlined (const user = restoreView().$implicit) while multi-usage retains separate statements
  • βœ… Variable Naming Parity: Global monotonic variable naming (_r1, _r2, ...) matches NGTSC exactly
  • βœ… Consts Array Parity: Attribute ordering and marker values (3 for bindings, 4 for template directives) match NGTSC
  • βœ… OnPush Optimization: Root view listeners skip unnecessary restoreView()/resetView() calls for OnPush components
  • βœ… Listener Element Association: Correctly associates listeners with their parent elements for proper consts array ordering

Other Improvements

  • βœ… Event Binding Emission: Full support for (click)="handler()" with proper Ι΅Ι΅listener() emission
  • βœ… Rolldown/Vite Integration: Angular Linker plugin for Rolldown bundler compatibility
  • βœ… Deterministic Build Output: HashMap β†’ IndexMap for consistent ordering of inputs, outputs
  • βœ… Signal Inputs/Outputs: Full support for input(), input.required(), and output() signals

πŸ“ Known Limitations

  • i18n: Not fully implemented
  • Lazy Loading: Deferred blocks partially supported
  • Animations: Basic support only
  • View Encapsulation: Only Emulated mode
  • Source Maps: Not yet implemented

🎯 Roadmap

  • Complete i18n support
  • Full animation support
  • Source map generation
  • Angular CLI integration
  • Incremental compilation
  • Watch mode

πŸ“ License

MIT - Same as Angular


Built with ❀️ using Rust