diff --git a/docs/architecture/adr/0003-observable-data-services.md b/docs/architecture/adr/0003-observable-data-services.md index 2b9d72015..7c8edfee3 100644 --- a/docs/architecture/adr/0003-observable-data-services.md +++ b/docs/architecture/adr/0003-observable-data-services.md @@ -33,6 +33,14 @@ Chosen option: **Observable data services**, because - The work towards a reactive data model will allow us to adopt patterns like NGRX in the future should it be needed. +:::info Updated Guidance + +This ADR remains valid for business logic services, but [ADR 0029][signals] introduces Angular +Signals as the preferred approach over RxJS for view layer code (components, directives, pipes, and +UI-coupled services). + +::: + ### Example #### Organizations @@ -95,3 +103,4 @@ NGRX is the most popular Redux implementation for Angular. For more details, rea [observable]: https://blog.angular-university.io/how-to-build-angular2-apps-using-rxjs-observable-data-services-pitfalls-to-avoid/ [redux-motivation]: https://redux.js.org/understanding/thinking-in-redux/motivation +[signals]: ./0029-angular-signals.md diff --git a/docs/architecture/adr/0026-dotnet-dependency-injection-enhancements.md b/docs/architecture/adr/0026-dotnet-dependency-injection-enhancements.md index 2a85feb61..6d0a31aee 100644 --- a/docs/architecture/adr/0026-dotnet-dependency-injection-enhancements.md +++ b/docs/architecture/adr/0026-dotnet-dependency-injection-enhancements.md @@ -107,7 +107,7 @@ as they are expected to always be included in the host -- those services are `IL ## Considered options -- **Ad-hoc usage** - Where we are today, the `TryAdd` overloads are allowed to be used and are used +- **Ad hoc usage** - Where we are today, the `TryAdd` overloads are allowed to be used and are used occasionally throughout the codebase but they is no outside encouragement to use them. - **Encourage usage** - Start encouraging usage through team training and encouragement to use them in code reviews but don't make any automatic check to enforce usage. diff --git a/docs/architecture/adr/0029-angular-signals.md b/docs/architecture/adr/0029-angular-signals.md new file mode 100644 index 000000000..819eae8d3 --- /dev/null +++ b/docs/architecture/adr/0029-angular-signals.md @@ -0,0 +1,80 @@ +--- +adr: "0029" +status: "Accepted" +date: 2025-11-24 +tags: [clients, angular] +--- + +# 0028 - Adopt Angular Signals for Component State + + + +## Context and Problem Statement + +Angular has adopted a new reactive primitive, signals. Signals have various improvements over RxJS: +performance, simplicity, and deeper integrations into the rest of the framework. + +RxJS will become an optional dependency of Angular. Certain asynchronous workflows will still +benefit from RxJS (signals are synchronous). Furthermore, being a part of the core Angular library, +Angular signals cannot readily be used in non-Angular environments. + +As such, Signals should be the default when operating _in the view layer_: components, directives, +pipes, and services that are tightly coupled to the UI/Angular. Services that primarily deal with +business logic should prefer RxJS to maximize portability (or, even better, be moved to the Rust +SDK). + +## Decision + +Signal-based APIs (inputs, outputs, child queries) will be required in components and directives via +linting: + +- `@Input()` → `input()` +- `@Output()` → `output()` +- `@ViewChild`/`@ContentChild` → `viewChild()`/`contentChild()` + +Services tightly coupled to Angular should use signals. Services with non-presentational business +logic should prefer RxJS for portability. Use `toSignal()` and `toObservable()` to bridge between +RxJS and signals when necessary. + +## Implementation Plan + +New code must use signal-based APIs; existing code will be migrated gradually. Angular provides +automatic code migrations for signal +[inputs](https://angular.dev/reference/migrations/signal-inputs) and +[queries](https://angular.dev/reference/migrations/signal-queries). + +Much of `libs/components` was updated using these migrators: +https://github.com/bitwarden/clients/pull/15340 + +See the +[Angular Modernization Guide](https://contributing.bitwarden.com/contributing/code-style/web/angular-migration-guide/#signals) +for more information. + +## Consequences + +**Positive:** + +- Improved performance and simpler change detection +- Clear path to removing Zone.js dependency +- Better debugging experience +- Aligned with Angular's direction +- Simpler than RxJS for many common use cases + +**Negative:** + +- Temporary complexity during migration with mixed RxJS/Signals patterns +- Learning curve for team members unfamiliar with signals +- Migration effort required for existing codebase + +## Reasons against other options + +- Disallow usage of signals and only use RxJS for reactivity. + - This is a non-starter. Signals are being built into Angular. +- Continue the status quo of ad hoc usage. + - Having multiple ways to do the same thing leads to analysis paralysis and complicated code. + - Signals + OnPush change detection provide a clear path to removing Zone.js. With that comes + notable performance and debugging improvements. + +## Further reading + +- [Angular docs](https://angular.dev/guide/signals) diff --git a/docs/architecture/security/definitions.mdx b/docs/architecture/security/definitions.mdx index e4a7cb154..d7f6a6623 100644 --- a/docs/architecture/security/definitions.mdx +++ b/docs/architecture/security/definitions.mdx @@ -12,7 +12,7 @@ be able to do, and what they want to achieve, possibly even not having anything achieve, just the notion of "I want a secure product". A formal approach here is needed: to aid in communication and to also provide a clear set of goals -to achieve. This applies both to ad-hoc conversations in which the participants don't yet share a +to achieve. This applies both to ad hoc conversations in which the participants don't yet share a common understanding of security goals and the assumed attacker, but it also applies to long-standing assumed security we want to achieve for our clients, communication protocols, and cryptography. This is not limited to cryptographic topics. diff --git a/docs/contributing/code-style/web/angular.md b/docs/contributing/code-style/web/angular.md index 165ed03ad..f97616f45 100644 --- a/docs/contributing/code-style/web/angular.md +++ b/docs/contributing/code-style/web/angular.md @@ -212,7 +212,7 @@ component "Organization Reports Module" { @enduml ``` -## Reactivity ([ADR-0003](../../../architecture/adr/0003-observable-data-services.md)) +## Reactivity ([ADR-0003](../../../architecture/adr/0003-observable-data-services.md) & [ADR-0029](../../../architecture/adr/0029-angular-signals.md)) We make heavy use of reactive programming using [Angular Signals][signals] & [RxJS][rxjs]. Generally components should always derive their state reactively from services whenever possible.