tl;dr: we’ve begun some prototyping work around adding signals as a reactive primitive in Angular, in advance of a formal Request For Comments (RFC) which we plan to open soon. Prototyping early and in the open aligns with our team values and allows us to get the most out of an RFC.
If you’ve seen our talk from ng-conf 2022, Angular: A Design Review 10 Years Later, you know we’ve been thinking long and hard about some fundamental design decisions of the framework. Last year, we kicked off a long-term research project with an ambitious goal: to embrace fine-grained reactivity in the core of the framework.
In a fine-grained reactive web framework, components track which parts of the application’s data model they depend on, and are only synchronized with the UI when that model changes. This is fundamentally different from how Angular works today, where it uses zone.js to trigger global top-down change detection for the whole application.
We believe adding built-in reactivity to Angular unlocks many new capabilities, including:
- A clear and unified model for how data flows through an application.
- Built-in framework support for declarative derived state (a common feature request).
- Synchronizing only the parts of the UI that needs updated, at or even below the granularity of individual components.
- Significantly improved interoperability with reactive libraries such as RxJS.
- Better guardrails to avoid common pitfalls that lead to poor change detection performance and avoid common pain points such as
ExpressionChangedAfterItHasBeenChecked
errors. - A viable path towards writing fully zoneless applications, eliminating the overhead, pitfalls, and quirks of zone.js.
- Simplification of many framework concepts, such as queries and lifecycle hooks.
Changing the reactivity model of an established framework like Angular is a significant project, with numerous challenges. Our plan for this project is broken out into multiple phases:
- Research and development, experimenting with different approaches to reactivity.
- Selection of a candidate design.
- Prototyping of the initial design to demonstrate feasibility.
- One or more community Requests for Comment (RFCs) to explore tradeoffs and inform the final design.
- A developer preview of the core reactivity implementation.
- Iteration and expansion of the core implementation towards the full design.
- Collaboration with the community to bring the entire Angular ecosystem forward into a reactive future.
Over the last few months, we’ve progressed through the first and second stages of this project, and have converged on a design based on the well-known reactive primitive of signals. During our experimentation we felt that this design demonstrated the strongest alignment with our overall goals.
Signals are not a new idea in the framework space – Preact, Solid, and Vue all employ some version of this concept to great success. We’ve taken a lot of inspiration from these and other reactive frameworks, and we are especially grateful to Ryan Carniato of SolidJS for his willingness to share his expertise and experience in many conversations over the last year.
That said, requirements across frameworks differ widely, and we’ve designed our version of signals to both meet Angular’s specific needs and as well as take full advantage of Angular’s unique strengths. Even though it’s still in the prototype stage, there are a few aspects of our design which we’re particularly proud of:
- Lazy evaluation, which is both efficient and avoids the need for explicit batching operations
- A computation model which doesn’t require immutable data
- Flexible effect scheduling, allowing for seamless integration with Angular
- Clever use of
WeakRef
to avoid explicit lifecycle management of signals - Possibilities around using our compiler to optimize various reactive operations, such as scheduling effects to automatically minimize reflows when performing DOM operations
- Bidirectional integration story with RxJS reactivity
We’ve begun prototyping this design and will be integrating it into Angular over the next few months. We’re committed to our open source spirit and plan to conduct these prototyping efforts in the open. This prototyping is essential to proving that our design for signals in Angular is viable and allows us to progress to a community RFC. The RFC will cover the rationale for using signals and the detailed design of various parts (our implementation, integration with RxJS, and other topics related to this effort).
We strongly believe that adding built-in reactivity to Angular is in the long term best interest of the framework and its users, and look forward to sharing more information about this project in the upcoming RFC.
FAQ
When will the RFC be?
Sometime later this year, depending on how smoothly the prototyping efforts progress.
Why signals as the reactive primitive?
This is a great question, and one which will be thoroughly discussed in the upcoming RFC. In short, signals have many of the properties we identified as desirable in a reactivity system designed for Angular, including:
- Values that are always available (synchronously)
- Reading a value does not trigger side effects
- Consistency between values (reads can’t show inconsistent state)
- Implicit, low overhead subscriptions
- Automatic and dynamic tracking of dependencies
Why are you committing code before the RFC?
There are a few reasons why we’ve chosen to begin prototyping before opening an RFC:
-
We feel having a real prototype will amplify the value we can gain from an RFC, as we will be able to share more detailed designs and ask more precise questions.
-
In any major design, there are challenges and constraints which only become visible at the scale of a full prototype. We want to uncover these and account for them in the RFC itself.
-
Many technical problems are unrelated to the overall reactivity system design (such as how it will integrate into Angular’s change detection algorithm). We want to tackle these problems sooner rather than later.
-
Google’s internal codebase has a different set of build tools and constraints than the external ecosystem, and early prototyping is necessary to validate our designs in that environment as well.
Leave A Comment