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
| Feature | Status | Description |
|---|---|---|
| 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
| Syntax | Status | Example |
|---|---|---|
| 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
| Property | Status | Details |
|---|---|---|
| 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 Type | Status |
|---|---|
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
| Metric | Rust Compiler | NGTSC (TypeScript) |
|---|---|---|
| Full Build (123 files) | ~2.88s | ~3.70s |
| Speedup | ~1.3x faster | Baseline |
| Memory Usage | Low (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
| Feature | Status | Notes |
|---|---|---|
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
| Feature | Status | Notes |
|---|---|---|
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
constsarray are sorted by their source position in the template, ensuring parity with NGTSC - β
Nested Loops: Full support for nested
*ngForwith 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"withTemplateRefextraction - β
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 (
3for bindings,4for template directives) match NGTSC - β
OnPush Optimization: Root view listeners skip unnecessary
restoreView()/resetView()calls forOnPushcomponents - β
Listener Element Association: Correctly associates listeners with their parent elements for proper
constsarray 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βIndexMapfor consistent ordering ofinputs,outputs - β
Signal Inputs/Outputs: Full support for
input(),input.required(), andoutput()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