Install

angular/angular

Angular Framework

Last updated on Dec 18, 2025 (Commit: 5a146b3)

Overview

Relevant Files
  • README.md
  • packages/README.md
  • packages.bzl
  • pnpm-workspace.yaml
  • package.json

Angular is a comprehensive development platform for building mobile and desktop web applications using TypeScript/JavaScript. This is the official Angular repository containing the framework source code, compiler, CLI tooling, and extensive documentation.

Repository Structure

The repository is organized as a monorepo using pnpm workspaces and Bazel for build management. It contains multiple interconnected packages that form the complete Angular ecosystem:

angular/
├── packages/          # Core framework packages published to npm
├── adev/              # Angular documentation site (angular.dev)
├── dev-app/           # Development application for testing
├── modules/           # Benchmarks and utilities
├── integration/       # Integration tests
├── tools/             # Build and development tools
└── devtools/          # Angular DevTools extension

Core Packages

The framework is distributed as 18 published npm packages:

Foundation Packages:

  • @angular/core – Runtime essentials including decorators (@Component, @Injectable), dependency injection, change detection, and lifecycle hooks
  • @angular/common – Fundamental directives, pipes, location services, HTTP client, and localization support
  • @angular/compiler – Template compiler for converting Angular templates to executable code
  • @angular/compiler-cli – Command-line compiler and build tooling (powers the Angular CLI)

Platform Packages:

  • @angular/platform-browser – Browser-specific rendering and DOM APIs
  • @angular/platform-browser-dynamic – JIT compilation support for browsers
  • @angular/platform-server – Server-side rendering (SSR) capabilities

Feature Packages:

  • @angular/router – Client-side routing and navigation
  • @angular/forms – Template-driven and reactive form handling
  • @angular/animations – Animation DSL and browser rendering
  • @angular/elements – Web Components integration
  • @angular/service-worker – Progressive Web App (PWA) support
  • @angular/localize – Internationalization (i18n) infrastructure
  • @angular/language-service – IDE integration and tooling support
  • @angular/upgrade – AngularJS to Angular migration utilities
  • @angular/benchpress – Performance benchmarking tools
  • zone.js – Asynchronous execution context management
  • angular-in-memory-web-api – Mock HTTP backend for development

Build System

The repository uses Bazel as the primary build system with TypeScript compilation. Key build artifacts:

  • npm packages – Published to npm registry under @angular/ scope
  • API documentation – Generated from TypeScript source code
  • Bundles – Optimized distribution formats (ESM, UMD, etc.)
  • Tests – Unit tests, integration tests, and e2e tests

Development Workflow

Loading diagram...

Key Technologies

  • TypeScript – Primary language for framework and tooling
  • RxJS – Reactive programming library for observables
  • Zone.js – Asynchronous context management
  • Bazel – Build and test orchestration
  • pnpm – Package manager (required, not npm or yarn)

Documentation & Resources

Architecture & Compilation Pipeline

Relevant Files
  • packages/compiler-cli/src/ngtsc/core/src/compiler.ts
  • packages/compiler-cli/src/ngtsc/program.ts
  • packages/compiler-cli/src/main.ts
  • packages/compiler/src/compiler.ts
  • packages/core/src/render3
  • packages/compiler/design/architecture.md

Overview

Angular's compilation pipeline transforms TypeScript source code with Angular decorators into optimized JavaScript and type definitions. The system uses ngtsc (the Ivy compiler) as the core engine, which wraps TypeScript's compiler and applies Angular-specific transformations. This architecture enables incremental compilation, template type-checking, and efficient code generation.

Compilation Architecture

The compilation process follows a layered architecture:

Loading diagram...

Key Components:

  1. NgCompilerHost - Wraps the TypeScript CompilerHost and injects synthetic Angular files (like __ng_typecheck__.ts for template type-checking).

  2. NgCompiler - The heart of the Ivy compiler. It's lazy-evaluated and only performs work when output methods are called (e.g., getDiagnostics(), emit()).

  3. Trait Compiler - Analyzes decorators (@Component, @Directive, @Injectable, @NgModule, @Pipe) and generates static definition fields (e.g., ɵcmp, ɵdir, ɵprov).

  4. Template Type Checker - Validates template expressions and bindings against component metadata.

Compilation Flow

The standard compilation sequence is:

  1. Configuration - Read tsconfig.json and merge with Angular compiler options
  2. Host Creation - Create NgCompilerHost wrapping the TypeScript compiler host
  3. Program Creation - Build ts.Program with augmented root files
  4. Ticket Generation - Create CompilationTicket (fresh or incremental)
  5. Compiler Initialization - Instantiate NgCompiler from the ticket
  6. Analysis - Analyze source files and extract decorator metadata
  7. Diagnostics - Gather TypeScript and Angular-specific diagnostics
  8. Emit - Call prepareEmit() to get Angular transformers, then emit JavaScript

Decorator Transformation

Angular decorators are compiled to static definition fields without runtime overhead:

Input (TypeScript):

@Component({
  selector: 'greet',
  template: '<div>Hello {{name}}</div>'
})
export class GreetComponent {
  @Input() name: string;
}

Output (JavaScript):

class GreetComponent {}
GreetComponent.ɵcmp = ɵɵdefineComponent({
  type: GreetComponent,
  tag: 'greet',
  factory: () => new GreetComponent(),
  template: function(rf, ctx) {
    if (rf & RenderFlags.Create) {
      ɵɵelementStart(0, 'div');
      ɵɵtext(1);
      ɵɵelementEnd();
    }
    if (rf & RenderFlags.Update) {
      ɵɵadvance();
      ɵɵtextInterpolate1('Hello ', ctx.name, '!');
    }
  }
});

Incremental Compilation

The compiler supports two incremental strategies:

  • Local Reuse - New NgCompiler inherits local metadata from previous compilation; global information (NgModule scopes) is recomputed
  • Full Reuse - Previous NgCompiler is reused entirely for resource-only changes (e.g., modified CSS files)

The CompilationTicket abstraction shields consumers from managing NgCompiler lifecycle complexity.

Render3 Runtime

The packages/core/src/render3 directory contains the runtime engine that executes compiled templates. It includes:

  • Instructions - Low-level rendering operations (ɵɵelementStart, ɵɵproperty, ɵɵlistener, etc.)
  • Change Detection - Efficient dirty-checking and signal-based reactivity
  • Dependency Injection - Service resolution and provider management
  • View Management - DOM node lifecycle and view container operations

Core Runtime & Dependency Injection

Relevant Files
  • packages/core/src/di/r3_injector.ts
  • packages/core/src/di/provider_collection.ts
  • packages/core/src/application/application_ref.ts
  • packages/core/src/application/application_init.ts
  • packages/core/src/render3/di.ts
  • packages/core/src/render3/component.ts

Dependency Injection System

Angular's DI system is built on the R3Injector, a hierarchical container that manages service instantiation and dependency resolution. The injector maintains a map of provider tokens to their corresponding factory functions and cached instances.

Key Components:

  1. Providers – Define how services are created. Five main types exist:

    • Type Provider: MyService – Class is both token and factory
    • Value Provider: {provide: Token, useValue: instance} – Pre-created value
    • Factory Provider: {provide: Token, useFactory: () => instance} – Custom factory function
    • Class Provider: {provide: Token, useClass: AltClass} – Alternative class implementation
    • Existing Provider: {provide: Token, useExisting: OtherToken} – Alias to another token
  2. Provider Processing – When an injector is created, it processes all providers:

    • Converts each provider to a Record containing a factory function and cached value
    • Handles multi-providers (arrays of values for a single token)
    • Resolves forward references and validates provider definitions
  3. Dependency Resolution – When inject(Token) is called:

    • Looks up the token in the injector's records
    • If not found, checks if the token has an @Injectable() decorator with a factory
    • Executes the factory function, passing resolved dependencies
    • Caches the result to ensure singleton behavior
// Example: Injector resolution flow
const injector = createInjector(AppModule);
const service = injector.get(MyService);  // Triggers factory execution
const cached = injector.get(MyService);   // Returns cached instance

Application Runtime & Initialization

The application runtime orchestrates component bootstrapping and lifecycle management through the ApplicationRef and ApplicationInitStatus classes.

Bootstrap Sequence:

  1. Platform CreationcreatePlatform() establishes the root injector with platform-level providers (NgZone, RendererFactory2, etc.)

  2. Application InjectorbootstrapApplication() creates an environment injector with app-level providers, inheriting from the platform injector

  3. InitializersAPP_INITIALIZER tokens are executed in sequence. They can return Promises or Observables to delay app startup:

bootstrapApplication(AppComponent, {
  providers: [
    {
      provide: APP_INITIALIZER,
      useValue: () => inject(HttpClient).get('/config'),
      multi: true
    }
  ]
});
  1. Component Bootstrap – The root component is instantiated via ComponentFactory.create(), which:

    • Creates an element injector for the component
    • Resolves component dependencies
    • Triggers change detection and renders the view
  2. Change DetectionApplicationRef.tick() synchronizes the application state with the DOM, running change detection cycles until stability is reached.

Hierarchical Injector Architecture

Angular uses a multi-level injector hierarchy:

Loading diagram...
  • Platform Injector: Singleton services shared across all applications
  • Environment Injector: Application-level services and providers
  • Component Injector: Component-specific providers and view providers

When resolving a dependency, the injector checks its own records first, then delegates to the parent injector if not found. This enables provider overrides at any level.

Injection Context

The inject() function requires an active injection context. This context is automatically established during:

  • Component/directive construction
  • Factory function execution
  • Initializer execution (via runInInjectionContext())

Attempting to call inject() outside these contexts throws an error. Use runInInjectionContext(injector, fn) to manually establish a context when needed.

Change Detection & Reactivity

Relevant Files
  • packages/core/primitives/signals
  • packages/core/src/render3/reactivity
  • packages/core/src/change_detection
  • packages/core/src/render3/reactive_lview_consumer.ts

Angular's change detection system is built on a reactive graph of signals and effects. When a signal value changes, the framework automatically detects which components and effects depend on it and schedules updates.

The Reactive Graph

At the core is a bidirectional dependency graph connecting producers (signals that emit values) and consumers (effects, computed signals, and templates that depend on those values).

// Producers: signals that emit values
const count = signal(0);
const doubled = computed(() => count() * 2);

// Consumers: effects that react to changes
effect(() => console.log(doubled()));

Each node in the graph tracks:

  • version: incremented when the value changes
  • dirty: whether the node needs recomputation
  • producers: signals this consumer depends on
  • consumers: effects/computeds that depend on this producer

Glitch-Free Execution: Push/Pull Algorithm

Angular prevents glitches (observing inconsistent intermediate states) using a two-phase algorithm:

Phase 1 (Push): When a signal updates, the framework eagerly propagates change notifications through the graph, marking all affected consumers as dirty. No recomputation happens yet.

Phase 2 (Pull): When values are read, the framework lazily recomputes only what's needed. This ensures all dependencies are invalidated before any consumer re-executes.

const counter = signal(0);
const isEven = computed(() => counter() % 2 === 0);
effect(() => console.log(counter(), isEven())); // Logs: 0 false

counter.set(1); // Phase 1: marks isEven and effect as dirty
                // Phase 2: effect re-runs, reads counter (1) and isEven (recomputes to true)

Live vs. Non-Live Consumers

Live consumers (effects, templates) receive push notifications when dependencies change. Non-live consumers (unused computed signals) poll their dependencies when accessed, preventing memory leaks.

const counter = signal(1);
let double = computed(() => counter() * 2);
console.log(double()); // 2
double = null; // Can be garbage collected—no hard reference from counter

// But if used in an effect:
effect(() => console.log(double())); // Now double is "live"

Dynamic Dependency Tracking

Dependencies are tracked implicitly during execution. If a computed signal conditionally reads different signals, the dependency set updates automatically:

const useA = signal(true);
const dataA = signal('A');
const dataB = signal('B');

const dynamic = computed(() => useA() ? dataA() : dataB());
// Dependencies: [useA, dataA] initially
// If useA changes to false, dependencies become [useA, dataB]

Change Detection Scheduling

The ChangeDetectionScheduler coordinates when change detection runs. With zoneless change detection, the framework schedules updates based on:

  • Signal updates in templates
  • ChangeDetectorRef.markForCheck()
  • Input property changes
  • Bound event listeners
bootstrapApplication(MyApp, {
  providers: [provideZonelessChangeDetection()]
});

Template Reactivity

Templates are treated as reactive consumers. Each component view gets a ReactiveLViewConsumer that tracks which signals are read during rendering. When those signals change, the view is marked for refresh.

@Component({
  template: `Count: {{count()}}`
})
export class MyComponent {
  count = signal(0);
  // Template automatically re-renders when count changes
}

Routing & Navigation

Relevant Files
  • packages/router/src/router.ts
  • packages/router/src/directives/router_outlet.ts
  • packages/router/src/directives/router_link.ts
  • packages/router/src/router_state.ts
  • packages/router/src/models.ts
  • packages/router/src/events.ts
  • packages/router/src/url_tree.ts
  • packages/router/src/recognize.ts

The Angular Router manages application state transitions and URL synchronization. It enables declarative navigation between views while maintaining browser history and supporting advanced features like lazy loading, guards, and resolvers.

Core Architecture

The router operates through three main components:

  1. Router Service - Orchestrates navigation, manages state, and exposes APIs like navigate() and navigateByUrl()
  2. RouterOutlet Directive - Placeholder that dynamically renders components based on the active route
  3. RouterLink Directive - Declarative navigation trigger that creates links without full page reloads
Loading diagram...

Route Configuration & Matching

Routes are defined as an array of Route objects that map URL paths to components. The router uses a hierarchical matching algorithm:

  • Path matching: Segments are matched against route configurations sequentially
  • Redirects: Routes can redirect to other paths using redirectTo
  • Lazy loading: Child routes can be loaded on-demand via loadChildren
  • Wildcards: The ** path matches any unmatched URL (typically for 404 pages)
const routes: Route[] = [
  { path: 'home', component: HomeComponent },
  { path: 'user/:id', component: UserComponent },
  { path: 'admin', loadChildren: () => import('./admin/routes') },
  { path: '**', component: NotFoundComponent }
];

When navigation is triggered, the router executes this sequence:

  1. URL Parsing - Converts the target URL into a UrlTree structure
  2. Route Recognition - Matches URL segments against configured routes
  3. Guard Execution - Runs canActivate, canDeactivate, and canMatch guards
  4. Data Resolution - Executes resolvers to fetch required data
  5. Component Activation - Creates component instances and injects them into RouterOutlet
  6. Event Emission - Fires navigation events (NavigationStart, NavigationEnd, etc.)

RouterOutlet acts as a placeholder where routed components are rendered:

&lt;router-outlet /&gt;

The outlet registers with ChildrenOutletContexts and receives activated routes from the router. It supports named outlets for complex layouts with multiple independent navigation branches.

RouterLink provides declarative navigation:

&lt;a routerLink="/user/42"&gt;View User&lt;/a&gt;
&lt;a [routerLink]="['/team', teamId, 'user', userId]"&gt;Team Member&lt;/a&gt;

RouterLink handles relative paths (./, ../), query parameters, and fragments while preventing default link behavior.

Router State & ActivatedRoute

The RouterState represents the current navigation tree as a hierarchy of ActivatedRoute instances. Each route node contains:

  • params - Route parameters (e.g., :id from /user/42)
  • queryParams - Query string parameters
  • data - Static route metadata
  • component - The component instance for this route
  • snapshot - Immutable view of the route at a specific moment

Components access route information via dependency injection:

constructor(private route: ActivatedRoute) {
  this.route.params.subscribe(params => {
    console.log(params['id']);
  });
}

The router emits events throughout the navigation lifecycle via router.events:

  • NavigationStart - Navigation begins
  • RoutesRecognized - Routes matched successfully
  • GuardsCheckStart / GuardsCheckEnd - Guard execution
  • ResolveStart / ResolveEnd - Data resolution
  • NavigationEnd - Navigation completed successfully
  • NavigationCancel - Navigation cancelled by guard
  • NavigationError - Navigation failed with error

Applications can subscribe to these events for logging, analytics, or UI updates.

Forms & Validation

Relevant Files
  • packages/forms/src/validators.ts
  • packages/forms/src/model/form_control.ts
  • packages/forms/src/model/form_group.ts
  • packages/forms/src/form_builder.ts
  • packages/forms/src/directives/ng_model.ts
  • packages/forms/src/directives/validators.ts

Angular Forms provides two complementary approaches for building and validating forms: Reactive Forms and Template-Driven Forms. Both leverage a unified validation system that supports synchronous validators, asynchronous validators, and custom validation logic.

Form Models

The core form model consists of three fundamental classes:

  • FormControl - Tracks the value and validation status of a single form field. Accepts an initial value, optional validators, and async validators.
  • FormGroup - Aggregates multiple FormControl instances into a single object. Its status is derived from its children (invalid if any child is invalid).
  • FormArray - Similar to FormGroup but for dynamic lists of controls, useful for variable-length form sections.

All three extend AbstractControl, which provides common methods like setValue(), patchValue(), reset(), and updateValueAndValidity().

Validation System

Validators are functions that receive a control and return either null (valid) or a ValidationErrors object (invalid). Angular provides built-in validators through the Validators class:

  • required - Control must have a non-empty value
  • min(n) / max(n) - Numeric bounds validation
  • minLength(n) / maxLength(n) - String/array length validation
  • email - Email format validation using RFC-compliant regex
  • pattern(regex) - Custom regex pattern matching

Validators can be composed using Validators.compose() to combine multiple validators into a single function.

Async Validators

Async validators return Promise&lt;ValidationErrors | null&gt; or Observable&lt;ValidationErrors | null&gt;. Common use cases include server-side validation (checking username availability) or expensive computations. The form enters a PENDING status while async validators run.

Register async validators via the asyncValidators option in AbstractControlOptions or through the NG_ASYNC_VALIDATORS injection token for directive-based validation.

Reactive vs Template-Driven Forms

Reactive Forms use FormBuilder or direct control instantiation:

const form = new FormGroup({
  email: new FormControl('', [Validators.required, Validators.email]),
  age: new FormControl(null, Validators.min(18))
});

Template-Driven Forms use directives like ngModel and ngForm:

&lt;form #myForm="ngForm"&gt;
  &lt;input [(ngModel)]="user.email" name="email" required email&gt;
&lt;/form&gt;

Error Handling

Access validation errors via the errors property, which is a map of error codes to error details:

control.errors // { required: true } or { email: true } or null
control.hasError('required') // boolean check
control.getError('required') // get specific error details

Form status is tracked as VALID, INVALID, PENDING (async validation in progress), or DISABLED.

Custom Validators

Implement the Validator or AsyncValidator interface to create reusable validators:

@Directive({
  selector: '[appCustomValidator]',
  providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}]
})
export class CustomValidatorDirective implements Validator {
  validate(control: AbstractControl): ValidationErrors | null {
    return control.value === 'forbidden' ? { forbidden: true } : null;
  }
}

Register via NG_VALIDATORS (sync) or NG_ASYNC_VALIDATORS (async) injection tokens with multi: true to add to existing validators.

Platform Rendering & SSR

Relevant Files
  • packages/platform-browser/src/browser.ts
  • packages/platform-server/src/server.ts
  • packages/platform-browser/src/hydration.ts
  • packages/core/src/hydration/annotate.ts
  • packages/core/src/hydration/utils.ts
  • packages/core/src/render3/instructions/render.ts

Overview

Angular supports two distinct rendering platforms: browser rendering for client-side execution and server rendering for server-side execution. The platform abstraction allows the same Angular application code to run in both environments. Hydration bridges these two worlds by enabling the client to reuse the server-rendered DOM instead of re-rendering from scratch.

Platform Architecture

The platform system is built on two main packages:

  • @angular/platform-browser - Provides browser-specific providers and the bootstrapApplication function for client-side rendering
  • @angular/platform-server - Provides server-specific providers and renderApplication for server-side rendering

Both platforms share the same core rendering engine (Render3) but with platform-specific implementations for DOM manipulation, event handling, and HTTP requests.

Loading diagram...

Server-Side Rendering Flow

When rendering on the server, Angular executes the component tree and produces an HTML string:

  1. Setup - provideServerRendering() sets ngServerMode = true globally
  2. Execution - Components execute their templates, creating a virtual DOM tree
  3. Annotation - annotateForHydration() marks components with hydration metadata (the ngh attribute)
  4. Serialization - Hydration data is serialized into TransferState and embedded in the HTML
  5. Output - The HTML string is sent to the client

Client-Side Hydration

Hydration reuses the server-rendered DOM instead of creating new elements:

  1. Detection - Client checks for ngh attributes and TransferState data
  2. Retrieval - retrieveHydrationInfo() extracts serialized view data from TransferState
  3. Reconciliation - Render instructions locate existing DOM nodes instead of creating new ones
  4. Attachment - Event listeners and component state are attached to existing elements
  5. Cleanup - Unclaimed DOM nodes are removed

The ngh attribute contains an index referencing serialized view data in TransferState under the key __nghData__.

Render3 Instructions

Both platforms use the same Render3 instruction set. Key instructions include:

  • Creation mode (rf & 1) - ɵɵelement, ɵɵtext, ɵɵtemplate create or locate DOM nodes
  • Update mode (rf & 2) - ɵɵproperty, ɵɵattribute, ɵɵlistener bind data and events

During hydration, creation instructions switch from creating new nodes to locating existing ones using paths stored in the serialized view data.

Hydration Features

Angular provides optional hydration features via provideClientHydration():

  • DOM Reuse - Default; reuses server-rendered DOM
  • Event Replay - withEventReplay() captures and replays user events before hydration completes
  • Incremental Hydration - withIncrementalHydration() hydrates components on-demand using the hydrate trigger
  • HTTP Transfer Cache - withHttpTransferCacheOptions() transfers HTTP responses from server to client
  • i18n Support - withI18nSupport() enables hydration for internationalized content

Mismatch Detection

In development mode, Angular validates that client and server DOM structures match:

  • Node Lookup - locateNextRNode() finds expected nodes using serialized paths
  • Validation - validateMatchingNode() checks node type, tag name, and content
  • Error Reporting - Mismatches throw NG0500 errors with detailed expected vs. actual DOM descriptions
  • DevTools Integration - Mismatch info is attached to component host elements for debugging

Key Constraints

Hydration requires strict DOM consistency between server and client:

  • HTML produced by server rendering must not be modified before client bootstrap
  • Whitespace and comment nodes must match exactly
  • Components with i18n blocks or ShadowDOM encapsulation skip hydration (marked with ngSkipHydration)
  • Dynamic content must use the same logic on both server and client

Build System & Tooling

Relevant Files
  • BUILD.bazel - Root build configuration
  • MODULE.bazel - Bazel module dependencies and toolchain setup
  • .bazelrc - Bazel configuration flags and settings
  • tools/bazel/ - Custom Bazel rules and build utilities
  • tools/defaults.bzl - Shared build rule definitions
  • scripts/build/ - Build scripts for distribution packages
  • contributing-docs/building-with-bazel.md - Detailed build documentation

Angular uses Bazel as its primary build system, providing fast, reliable incremental builds across the monorepo. The build infrastructure is complemented by pnpm for package management and custom tooling for specialized tasks.

Bazel: The Core Build System

Bazel is a polyglot build tool that enables hermetic, reproducible builds. Angular's Bazel setup includes:

  • Module System (MODULE.bazel): Declares dependencies on Bazel rules and external tools

    • aspect_rules_ts for TypeScript compilation
    • aspect_rules_js for JavaScript bundling
    • aspect_rules_esbuild for ES module bundling
    • rules_angular for Angular-specific compilation rules
    • Node.js toolchain (v22.21.1) and pnpm (v10.16.1)
  • Configuration (.bazelrc): Sets build flags for consistency

    • Symlink prefix: dist/ for outputs
    • Strict action environment for cache consistency
    • Debug mode with --config=debug for test inspection
    • Release stamping with version control information
  • Custom Rules (tools/bazel/): Specialized build rules for Angular

    • ng_package - Builds distributable Angular packages
    • ng_web_test_suite - Runs browser-based tests with Karma
    • esbuild - Bundles and minifies code
    • jasmine_test - Runs Node.js tests with Jasmine

Building and Testing

Common build commands:

pnpm bazel build packages/core              # Build a single package
pnpm bazel build packages/...               # Build all packages
pnpm bazel test packages/core/test:test     # Run Node tests
pnpm bazel test packages/core/test:test_web # Run browser tests

Use ibazel for watch mode: ibazel build packages/core continuously rebuilds as files change.

Package Management

Angular uses pnpm (v10.26.0) as the package manager:

  • Monorepo workspace defined in pnpm-workspace.yaml
  • Lock file: pnpm-lock.yaml (frozen mode enforced in .bazelrc)
  • Custom patches in tools/pnpm-patches/ for dependency fixes
  • All npm dependencies managed through Bazel's npm_translate_lock extension

Distribution Build

The scripts/build/ directory contains TypeScript scripts for building distribution packages:

  • build-packages-dist.mts - Main entry point for pnpm build
  • package-builder.mts - Orchestrates package compilation and bundling
  • zone-js-builder.mts - Specialized builder for Zone.js package

Run with: pnpm build

Debugging and Profiling

Debug Node Tests:

pnpm bazel test packages/core/test:test --config=debug

Then attach debugger at chrome://inspect or VSCode port 9229.

Profile Builds:

pnpm bazel build //packages/compiler --profile profile.json
pnpm bazel analyze-profile profile.json --html --html_details

Key Configuration Highlights

  • Hermetic Builds: All dependencies declared explicitly; no implicit filesystem access
  • Remote Caching: Supported on CI; available to core developers with credentials
  • Stamping: Release builds include git commit info via workspace_status_command
  • Cross-Platform: Supports Linux, macOS (Intel & ARM), and Windows with platform-specific toolchains