angular/angular
github.com/angular/angular ↗ · 3997 files · 10.8 MB · scan capped
Angular - The modern web developer's platform Angular is a development platform for building mobile and desktop web applications using TypeScript/JavaScript and other languages.
Overview
Angular is a TypeScript framework for building web applications, with application bootstrapping, reactive state, templates, routing, forms, HTTP, server rendering, and offline support implemented in this repository. The same monorepo contains angular.dev, its interactive tutorial runtime, browser DevTools, and the VS Code extension. At commit 831cb13e1c6e5ff17da23273109772c2b088302e, standalone application creation installs zoneless scheduling by default, while pnpm and Bazel organize development and verification. This brief is a bounded source investigation; tests, builds, workflows, and external services were not executed.
System map
The repository combines framework libraries with documentation, developer tooling, and distribution automation. Runtime application creation separates browser platform providers from application providers, while server rendering supplies a request-specific platform. Persistent state differs by subsystem: documentation history uses localStorage and the service worker uses CacheStorage. pnpm scripts delegate most builds and tests to Bazel, and GitHub workflows separate product checks from publishing.
- The private root package is angular-srcs version 22.3.0-next.0 and pins pnpm 11.27.1; its dependencies link framework packages through workspace:*.
- pnpm-workspace.yaml includes framework libraries, adev/shared-docs, dev-app, DevTools, integration projects, Zone.js, and the VS Code client/server workspaces.
- adev/src/main.ts boots AppComponent with appConfig; appConfig registers hydration, router providers, Algolia search, analytics initialization, document loaders, and a TypeScript worker provider.
- bootstrapApplication assembles browser providers and delegates to internalCreateApplication, which creates an application injector under the platform injector and installs zoneless scheduling.
- Compilation has distinct template parsing and TypeScript annotation-analysis layers: parseTemplate constructs HTML and binding parsers, while ComponentDecoratorHandler implements DecoratorHandler for @Component.
- renderApplication creates a server platform, passes it into the application's bootstrap callback, waits for stability, renders, and destroys the platform in finally.
- Documentation history owns an in-memory signal-backed Map and serializes it to localStorage; service-worker CacheDatabase instead stores JSON in Response objects inside CacheStorage.
- Browser DevTools connects a Chrome runtime port to a same-page message bus, injecting backend_bundle.js into the inspected document after Angular detection.
- pnpm build invokes build-packages-dist.mts; package-builder queries npm_package targets tagged release-with-framework, stamps their versions, and copies outputs into dist/packages-dist.
- Adev is configured to prerender all routes; push CI builds its production artifact and deploys through the docs-site action, while package releases delegate to a pinned angular/dev-infra reusable workflow.
Feature catalog
The user-facing surface includes framework APIs for application authors and separate tools for learning, debugging, and editing Angular applications. Angular.dev exposes documentation, reference pages, tutorials, a playground, and update guidance through generated and explicit routes. DevTools exposes component, routing, injector, profiling, and signal inspection operations. The catalog covers the inspected feature families; the bounded inventory does not establish exhaustive coverage of every API or screen.
- bootstrapApplication renders a standalone root component, while createApplication creates the application environment without bootstrapping a component.
- Writable signals expose set, update, and asReadonly; underlying signal writes compare values before incrementing versions and notifying consumers.
- Template parsing supports configurable whitespace handling, @ block syntax, @let syntax, selectorless syntax, i18n metadata, and parse diagnostics.
- Router.navigateByUrl accepts strings or UrlTree values, and the navigation pipeline supports guards, resolvers, lazy component loading, route reuse, and view transitions.
- Typed FormGroup accepts synchronous and asynchronous validators; setValue checks the complete group shape, updates child controls, and recomputes group validity.
- HttpClient constructs requests with credentials, cache, timeout, integrity, and progress options; FetchBackend supports response parsing and download progress but rejects upload-progress requests.
- Server rendering returns HTML after application stability, and adev enables client hydration alongside prerendering of every route.
- The service-worker Driver handles fetch, message, push, notification-click, notification-close, and push-subscription-change events; fetch handling selects an application version and falls back to the network when needed.
- createCustomElement turns an Angular component into a custom-element constructor, maps observed attributes to inputs, and connects a configurable component strategy.
- The localize initialization entrypoint installs $localize on globalThis; the upgrade static entrypoint exports downgradeComponent, downgradeInjectable, downgradeModule, UpgradeComponent, and UpgradeModule.
- The animation metadata API still exposes animation(), explicitly deprecated since 20.2 in favor of animate.enter or animate.leave, with an expressed removal intent for v23.
- Angular.dev routes include home, documentation, API references, CLI references, tutorials, playground, update guide, redirects, footer content, and a wildcard not-found page.
Data flow
Framework inputs move through provider-configured pipelines rather than a single application backend. Bootstrap configuration produces injectors and component instances; navigation produces resolved route data and rendered views. HTTP requests become interceptor chains and Fetch events, while documentation search transforms remote records into signal-owned UI state and browser persistence. The service worker owns separate version-assignment and cache-backed state.
- Root component and ApplicationConfig inputs become browser appProviders and platformProviders, then an EnvironmentNgModuleRefAdapter whose injector is passed to bootstrap.
- Signal getters call producerAccessed to track reads; changed writes update node.value, increment node.version and the producer epoch, and notify dependent consumers.
- Template text enters HtmlParser with source-mapping options; i18n metadata is processed before whitespace removal so message IDs retain their expected source relationship.
- navigateByUrl parses and merges a UrlTree, scheduleNavigation registers a pending task, and handleNavigationRequest receives current snapshots, navigation options, and promise completion callbacks.
- Documentation navigation metadata becomes route.data and a docContent resolver; that resolver injects DOCS_CONTENT_LOADER and passes contentPath to getContent.
- ContentLoader normalizes missing extensions to .md.html, fetches assets/content/{path} as text, produces {contents, id}, and caches the Promise by normalized path.
- DocsComponent receives resolved DocContent as an input; its template passes contents to DocViewer, whose effect renders HTML and installs client-side controls before emitting contentLoaded.
- HttpClient constructs HttpRequest and invokes the handler per subscription; HttpInterceptorHandler deduplicates interceptors, composes them in registration order, and removes its stability task through finalize.
- FetchBackend serializes request bodies and headers into RequestInit, reads response chunks, parses the requested body type, and emits either HttpResponse or HttpErrorResponse.
- SearchQuery drives a debounced resource; Algolia hits become SearchResultItem records, while history clicks copy those records into a signal-backed Map and serialize sorted items to localStorage.
- The service worker restores manifests, client assignments, and the latest version from its control table; CacheTable maps keys to requests and stores values as JSON responses.
Behavior traces
The investigation followed application startup, documentation navigation, and search-history persistence across their source boundaries. Additional traces cover HTTP, server rendering, tutorials, DevTools transport, and service-worker restoration. These are ordered source walkthroughs, not observed runtime executions. Each trace names the functions or operations that establish its behavior.
- Startup, stage 1: adev main calls bootstrapApplication(AppComponent, appConfig); bootstrapApplication calls createProvidersConfig and then internalCreateApplication.
- Startup, stage 2: internalCreateApplication creates or reuses the platform injector, constructs EnvironmentNgModuleRefAdapter, and calls bootstrap; bootstrap resolves injector initializers and waits for ApplicationInitStatus.donePromise.
- Startup, stage 3: bootstrap calls ApplicationRef.bootstrap(rootComponent); ApplicationRef creates a ComponentFactory and ComponentRef, then _loadComponent attaches the view, calls tick, and invokes bootstrap listeners.
- Documentation navigation, stage 1: Router construction installs and subscribes to the setupNavigations transition stream. navigateByUrl calls scheduleNavigation, which passes request state to handleNavigationRequest; that pushes into the stream whose pipeline checks guards, resolves route data, and loads lazy components.
- Documentation navigation, stage 2: the generated docContent resolver calls ContentLoader.getContent; resolved input reaches DocsComponent and DocViewer.renderContentsAndRunClientSetup, which writes HTML, loads examples, and builds navigation aids.
- Search persistence: SearchDialog binds form(searchQuery); debounced resultsResource calls searchWithQuery and parseResult; clicking a result invokes history.addItem → updateHistory → localStorage.setItem, and a later SearchHistory constructor calls loadHistory to restore the Map.adev/shared-docs/components/search-dialog/search-dialog.component.ts#L57-72adev/shared-docs/services/search.service.ts#L50-60adev/shared-docs/components/search-dialog/search-dialog.component.html#L14-19adev/shared-docs/services/search-history.service.ts#L95-120adev/shared-docs/services/search.service.ts#L189-229adev/shared-docs/services/search-history.service.ts#L48-73
- HTTP action: HttpClient.request constructs HttpRequest and runs HttpInterceptorHandler.handle on subscription; its chain reaches xsrfInterceptorFn and FetchBackend.handle → doRequest → parseBody, followed by response or error emission.
- SSR action: renderApplication → validateAllowedHosts → createServerPlatform → bootstrap({platformRef}) → applicationRef.whenStable → renderInternal; asyncDestroyPlatform runs in finally.
- Tutorial action: NodeRuntimeSandbox.init → boot → startInteractiveTerminal → initProject → mountProjectFiles → installDependencies → loadTypes/startDevServer; server-ready forwards the generated preview URL.
- DevTools connection: chrome.runtime.connect creates the port; detectAngular triggers backend script injection and attemptBackendHandshake, which retries handshakeWithBackend every 500 ms until backendReady; onAny handlers relay messages between the two buses.
- Offline request: the fetch listener calls Driver.onFetch; accepted requests use handleFetch → ensureInitialized → assignVersion → AppVersion.handleFetch, with safeFetch fallbacks; initialize restores the control-table records through CacheTable.read.
Testing signals
Tests and CI were inspected, not executed; a test's existence is not a passing result. The framework uses Bazel targets with Jasmine and browser test suites, while DevTools also has Cypress and Zone.js has multiple runner integrations. Inspected assertions cover HTTP semantics, XSRF boundaries, history state, compiler behavior, route tables, and settings migration. Coverage observations are limited to the files read and do not establish whole-repository coverage or absence.
- Verification status is source inspection only: the declared test commands and CI jobs were read, but no test, build, benchmark, or workflow was executed and no passing result is asserted.
- The HTTP test BUILD declares zoneless_jasmine_test named test and zoneless_web_test_suite named test_web, sharing TypeScript tests and TestBed dependencies.
- FetchBackend tests use TestBed, an injected MockFetchFactory, and Jasmine spies to assert immediate Sent events, subscription laziness, and retry behavior.
- Fetch tests assert download event sequencing, response headers, partial text, and rejection of upload-progress requests.
- XSRF tests distinguish GET/HEAD from POST, absolute and protocol-relative cross-origin requests from same-origin requests, and preservation of existing headers.
- SearchHistory tests assert storage serialization, ordering, deletion, favorites, and the recent-history limit using MockLocalStorage; their timestamp ordering helper uses real short timeouts.
- Adev routing smoke tests reject external and malformed route paths and load representative lazy components; despite the 'prerender' name, those assertions do not render a complete page or exercise real content fetching.
- ngtsc behavioral tests run through runInEachFileSystem and NgtscTestEnvironment; an inspected case writes a component and external template, invokes driveMain, and checks generated JavaScript.
- DevTools has direct assertions for injector path and edge construction and for V1-to-V2 settings migration; PR CI also runs DevTools unit tests, a Chrome build, and Cypress against the devserver.
- Framework test:ci excludes integration, adev, VS Code, DevTools, and SSR benchmarks; PR CI provides separate integration, adev, VS Code, and Zone.js jobs, with Zone.js invoking Jest, Vitest, Electron, and typings checks.
- createCustomElement contains a specific TODO requesting end-to-end coverage for cases where the constructor is not called and says that scenario is tested internally at Google; the internal test implementation and results were not available in this inspection.
Risk map
The following items are security-sensitive boundaries and maintenance observations, not confirmed vulnerabilities. HTML insertion, HTTP credentials, extension messaging, host build commands, and workflow trust transitions warrant focused review when changed. Source also exposes explicit compatibility constraints and limited validation at persistence boundaries. Any predicted failure is labeled as an inference, and partial inspection does not establish missing protections elsewhere.
- DomSanitizerImpl sanitizes HTML and URLs, rejects untrusted script/resource URLs, and exposes bypassSecurityTrust methods that deliberately disable those protections for supplied values.
- DocViewer assigns supplied content directly to nativeElement.innerHTML; this makes the generated document-content pipeline a trust boundary rather than an automatically sanitized Angular template binding.
- SamePageMessageBus emits window messages with targetOrigin '*', checks the receiving window and source marker, and updates bus status before those checks in on/onAny; the bridge also exposes updateState operations.
- FetchBackend buffers complete response chunks before parsing. Its default 1 MiB limit applies in SSR mode, while browser mode defaults to no limit; the implementation checks both declared content length and accumulated bytes.
- withCredentials overrides an explicit credentials setting to 'include'; XSRF skips GET/HEAD, disabled protection, invalid URLs, and cross-origin requests, so callers must understand these separate transport and token rules.
- Hypothesis: valid JSON of an unexpected shape in docs-search-history-v1 can break restoration because JSON.parse is caught but the subsequent iteration and item access have no shape validation in loadHistory. (inferred)
- package-builder uses execSync with command strings, accepts the BAZEL environment override, removes output directories, and interpolates paths without shell quoting; it is a host-side execution and filesystem boundary, not a read-only inspection helper.
- Tutorial sandbox code starts npm and bash processes and recursively removes files during cleanup, but these operations are issued through WebContainer rather than host child_process.
- Preview automation intentionally separates unprivileged PR building from credentialed deployment; benchmark comparison instead checks team membership before checking out and executing the PR head, making that approval boundary consequential.
- ComponentDecoratorHandler disables deferred dependencies during HMR because update modules cannot have dynamic imports; changing dependency deferral without preserving this coupling can alter generated HMR references.
- parseTemplate explicitly documents an existing ICU whitespace-context bug and preserves the current runtime representation; this is a source-acknowledged compatibility constraint, not a newly reproduced defect.
- The compiler architecture document is labeled Draft and discusses experimental Ivy and ngcc; its historical proposals should not be treated as proof of this commit's current runtime or distribution behavior.
Extension points
Angular primarily exposes extension seams through dependency-injection tokens, provider factories, and typed interfaces. Routing and HTTP provide configurable pipelines, while event handling has a concrete plugin registry. Documentation reuses injectable loaders and navigation metadata, and DevTools uses a typed event bus with registered handlers. Internal compiler and release registries are useful maintainer seams but are not automatically supported public extension APIs.
- ApplicationConfig.providers extends browser application providers; BootstrapContext supplies a pre-existing platform, and createApplication allows component creation to be separated from environment creation.
- provideHttpClient accepts HttpFeature values and appends their providers; withInterceptors registers functional interceptors, while withXsrfConfiguration customizes cookie and header names.
- FetchFactory permits injecting a fetch implementation, and HTTP_FETCH_MAX_RESPONSE_SIZE configures or disables the response-buffer limit.
- EVENT_MANAGER_PLUGINS supplies EventManagerPlugin instances; EventManager prioritizes custom plugins in reverse registration order, keeps the catch-all DOM plugin last, and caches the chosen plugin by event name.
- Adev demonstrates router customization through provideRouter features and replacements for RouteReuseStrategy and TitleStrategy, plus a custom UrlSerializer in application providers.
- DOCS_CONTENT_LOADER abstracts content retrieval; mapNavigationItemsToRoutes accepts additional Route properties, merges navigation data, and installs a replaceable docContent resolver.
- Adev injects PREVIEWS_COMPONENTS, EXAMPLE_VIEWER_CONTENT_LOADER, WINDOW, and the TypeScript worker provider, keeping shared documentation components separate from site-specific implementations.
- createCustomElement accepts config.strategyFactory and otherwise uses ComponentNgElementStrategyFactory; the resulting strategy mediates input changes and component connection.
- DevTools MessageBus<T> defines typed on, once, emit, and destroy operations; subscribeToClientEvents connects named protocol topics to backend callbacks.
- ComponentDecoratorHandler is an internal compiler handler with PRIMARY precedence, decorator detection, metadata registries, scope readers, a resource loader, and cached preanalysis results.
- Release package discovery is tag-based: package-builder queries npm_package targets bearing release-with-framework, with a special mapping for the language-server package.
Contributor handoff
Begin with repository conventions and the BUILD.bazel nearest the requested change, then trace the affected subsystem across its interfaces. Favor package-local edits and preserve public API, stability, platform, and message-protocol contracts. Tests and CI were inspected, not executed; future execution requires authorization compatible with the active task. This inventory and investigation are bounded, so recheck current source rather than assuming exhaustive coverage.
- Read AGENTS.md and the linked build, coding, and commit documentation first; the repository specifies pnpm and pnpm bazel test //target.
- New tests should follow the repository's zoneless Act, Wait, Assert convention with fixture.whenStable(), avoiding manual fixture.detectChanges(); useAutoTick and timeout are the documented timing helpers.
- Preserve formatting rules including a 100-column width, two-space indentation, single quotes, no bracket spacing, and trailing commas; HTML uses the Angular parser outside test paths.
- Respect public API boundaries: main and documented testing entrypoints are supported, while underscore/ɵ/ɵɵ members, compiler-generated contents, and core/primitives are excluded; public changes require golden review.
- For HTTP changes, read client.ts, provider.ts, backend.ts, fetch.ts, and xsrf.ts together; the smallest declared HTTP suites are pnpm bazel test //packages/common/http/test:test and //packages/common/http/test:test_web.
- For adev content or route changes, inspect routes.ts, navigation.utils.ts, ContentLoader, DocsComponent, and DocViewer; route smoke tests validate path shape and component loading but do not prove complete prerender success.
- For DevTools settings format changes, retain chronological migrations in applyMigrations; V1-to-V2 renames profiling and active-tab keys before writing the latest version back through ApplicationOperations.
- For startup or SSR changes, preserve asynchronous initializer ordering, PendingTasks cleanup, and the requirement for a server BootstrapContext; renderApplication waits for stability and always destroys its platform.
- Tests and CI were inspected, not executed. The documented future checks are separated across framework, integration, DevTools, adev, VS Code, and Zone.js jobs; their source declarations provide no evidence that this checkout passes.
- The build entrypoint performs snapshot builds and package-builder removes and copies generated directories; do not invoke pnpm build as an exploratory read-only check.
- Local downstream testing has documented traps: disable the Angular CLI disk cache when using locally built packages and invoke the CLI with preserve-symlinks flags so linked package resolution remains correct.
- Preserve workspace dependency behavior: pnpm disables hoisting and automatic peer installation to align its node_modules layout and dependency placeholders with Bazel rules_js.
Languages
| Language | Files | Share of source |
|---|---|---|
| TypeScript | 6072 | 85% |
| JavaScript | 934 | 13% |
| Markdown | 719 | docs/config |
| JSON | 539 | docs/config |
| HTML | 452 | docs/config |
| CSS | 321 | docs/config |
| Sass | 146 | 2% |
| YAML | 68 | docs/config |
Start reading here
Probable source entrypoint: packages/ — inferred from the directory tree and manifest, not the upstream docs.
Source roots
packages/ (1116 files)
Repository structure
| Top-level path | Files |
|---|---|
packages/ | 1116 |
adev/ | 1116 |
devtools/ | 637 |
integration/ | 410 |
modules/ | 235 |
vscode-ng-language-service/ | 150 |
tools/ | 84 |
goldens/ | 55 |
Docs found: AGENTS.mdCONTRIBUTING.mdREADME.md
Package
package.json — angular-srcs v22.3.0-next.0, 80 declared dependencies.
@actions/core@actions/github@angular-devkit/core@angular-devkit/schematics@angular/animations@angular/aria@angular/benchpress@angular/build@angular/cdk@angular/cli@angular/common@angular/compiler
CI & config entrypoints
README.md— Repository readmeAGENTS.md— Agent instructions.github/workflows/adev-preview-build.yml— GitHub Actions workflow.github/workflows/adev-preview-deploy.yml— GitHub Actions workflow.github/workflows/assistant-to-the-branch-manager.yml— GitHub Actions workflow.github/workflows/benchmark-compare.yml— GitHub Actions workflow.github/workflows/ci.yml— GitHub Actions workflow.github/workflows/cross-repo-adev-docs.yml— GitHub Actions workflow.github/workflows/dev-infra.yml— GitHub Actions workflow.github/workflows/google-internal-tests.yml— GitHub Actions workflow
Structural health signals
Average score 6.2/10 across 96 analyzed source files; 59 hotspots surfaced.
packages/common/http/test/provider_spec.ts— 949 lines, score 4 (Large file, Deep nesting)packages/common/http/test/transfer_cache_spec.ts— 1365 lines, score 4.7 (Large file, Deep nesting)packages/compiler-cli/src/ngtsc/typecheck/test/type_checker__get_symbol_of_template_node_spec.ts— 1254 lines, score 5 (Large file, Deep nesting)
These are deterministic review leads — size, churn, and structural signals — not proof of a bug in this project.
Recent history
831cb13e1c6e2026-10-01 — docs: note that the output migration rewrites piped outputs in test files860832591d582026-09-29 — docs(core): remove reference to ServerTransferStateModule from TransferStatea0bb74bf9a042026-09-20 — docs(platform-browser): link the styling guide from the namespacing APIs (#70835)95f607ca75392026-09-20 — docs: document CSS custom property namespacing in the styling guide (#70835)95383cdf28bc2026-09-26 — docs(router): note that shouldReuseRoute doesn't rerun guards and resolvers