The Domino DOM emulation library doesn't support shadow DOM. For such components we can not guarantee that client and server representations would match perfectly. To avoid hydration mismatch errors, such components are opted out of hydration.
PR Close#49722
Currently, non-destructive hydration for i18n blocks is not supported (but support is coming!).
This commit updates the serialization logic from throwing an error when it comes across an i18n
block to annotating a component with a skip hydration flag.
PR Close#49722
This commit adds a hook to `WritableSignal` that is called whenever the
signal's value is updated via the mutation API. This hook allows consumers
to implement logic which is synchronous with signal sets (e.g. executing
effects). It's currently unused.
PR Close#49708
Angular lifecycle hooks should never be run as part of the reactive
context: we do not expect that signal reads in lifecycle hooks
report to any consumers.
In the current Angular some of the lifecycle hooks can be flushed
early, while executting template update pass. We need to make sure
that signal reads in those lifecycle hooks do not register as part
of the effect that marks components for check.
"
PR Close#49701
`ComponentRef.setInput` internally calls `markDirtyIfOnPush` which only marks
the given view as dirty but does not mark parents dirty like `ChangeDetectorRef.markForCheck` would.
https://github.com/angular/angular/blob/f071224720f8affb97fd32fb5aeaa13155b13693/packages/core/src/render3/instructions/shared.ts#L1018-L1024
`markDirtyIfOnPush` has an assumption that it’s being called from the parent’s template. That is, we don’t need to mark dirty to the root, because we’ve already traversed down to it.
The function used to only be called during template execution for input
bindings but was added to `setInput` later. It's not a good fit because
it means that if you are responding to events such as an emit from an `Observable`
and call `setInput`, the view of your `ComponentRef` won't necessarily get checked
when change detection runs next. If this lives inside some `OnPush` component tree
that's not already dirty, it only gets refreshed if you also call
`ChangeDetectorRef.markForCheck` in the host component (because it will be "shielded" be a non-dirty parent).
PR Close#49711
Previously, attempting to turn off the `experimentalDecorators` TypeScript configuration
option within an Angular project would result in build time errors. These errors were due
to an exposed Decorator signature from `@angular/core` that TypeScript thought was incompatible
with standard decorators. However, Angular's class decorators (`Component`, `Directive`, `Pipe`,
`Injectable`, `NgModule`) are actually already compatible with standard decorators. The export types for
the decorators only needed to be updated to reflect that compatibility. With the updated exported types,
applications will now successfully compile and execute in AOT mode with one important dependency injection
caveat explained in the note below.
For JIT mode applications that are built with the Angular CLI, `@ngtools/webpack`, or use `tsickle`,
there were also no additional changes required. These tools automatically convert property decorators
(now called field decorators) at build time to store Angular property metadata directly on the relevant
class. Building with these tools is the overwhelmingly common method of building an application. Any
applications that do not use one of these tools will not function at runtime in JIT mode if using standard
decorators. The behavior and code for when experimental decorators is enabled has been left intact.
NOTE: Angular constructor dependency injection that requires parameter decorators is not supported.
The standard decorator specification does not support parameter decorators. The `inject` function must be
used for all cases that previously required a parameter decorator. This includes such decorators as `Inject`,
`Optional`, `Self`, `SkipSelf`, `Host`, and `Attribute`. Constructor dependency injection that relies only
on the supplied parameter type will continue to function as expected if using AOT; as well as in JIT mode
if using the Angular CLI, `@ngtools/webpack` directly, or `tsickle`.
Documentation for the `inject` function can be found at: https://angular.io/api/core/inject
The decorator specification proposal can be found at: https://github.com/tc39/proposal-decorators
PR Close#49492
The `ReflectiveInjector` symbol has been deprecated in v5 (11 major versions ago). This commit removes ReflectiveInjector and related symbols.
BREAKING CHANGE: The `ReflectiveInjector` and related symbols were removed. Please update the code to avoid references to the `ReflectiveInjector` symbol. Use `Injector.create` as a replacement to create an injector instead.
PR Close#48103
In modern browsers, the 'javascript:' URL scheme is the only scheme that
can execute JavaScript when passed in a navigation URL context (e.g.
`a.href` value). Validate URL shemes to only contain characters allowed
in the URL specification ([a-zA-Z-+.]), and that are not javascript
(case insensitive). This is not a breaking change. The URL sanitization
is loosen.
PR Close#49659
This commit adds the `provideClientHydration` function to the public API. This function can be used to enable the non-destructive Angular hydration.
Important note: the non-destructive hydration feature is in Developer Preview mode, learn more about it at https://angular.io/guide/releases#developer-preview.
Before you can get started with hydration, you must have a server side rendered (SSR) application. Follow the [Angular Universal Guide](https://angular.io/guide/universal) to enable server side rendering first. Once you have SSR working with your application, you can enable hydration by visiting your main app component or module and importing `provideClientHydration` from `@angular/platform-browser`. You'll then add that provider to your app's bootstrapping providers list.
```typescript
import {
bootstrapApplication,
provideClientHydration,
} from '@angular/platform-browser';
// ...
bootstrapApplication(RootCmp, {
providers: [provideClientHydration()]
});
```
Alternatively if you are using NgModules, you would add `provideClientHydration` to your root app module's provider list.
```typescript
import {provideClientHydration} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
@NgModule({
declarations: [RootCmp],
exports: [RootCmp],
bootstrap: [RootCmp],
providers: [provideClientHydration()],
})
export class AppModule {}
```
You can confirm hydration is enabled by opening Developer Tools in your browser and viewing the console. You should see a message that includes hydration-related stats, such as the number of components and nodes hydrated.
Co-authored-by: jessicajaniuk <72768744+jessicajaniuk@users.noreply.github.com>
Co-authored-by: alan-agius4 <17563226+alan-agius4@users.noreply.github.com>
PR Close#49666
To match the behaviour of Array.filter, typeguards can now be used on QueryList.filter to narrow the return type.
Fixes#38446
BREAKING CHANGE: QueryList.filter now supports type guard functions, which will result in type narrowing. Previously if you used type guard functions, it resulted in no changes to the return type. Now the type would be narrowed, which might require updates to the application code that relied on the old behavior.
PR Close#48042
This commit updates the logic to handle a case when the `ngSkipHydration` attribute is applied to the root node of an app. In this case, the hydration info should not be serialized and the contents of the app on the client should be cleared up before initial rendering.
PR Close#49675
This change exposes the onDestroy callback on the ApplicationRef
as the public API. It is useful for cases where people need to
execute cleanup logic on application teardown.
Closes#49087
PR Close#49677
This commit adds a provider function that allows developers to configure
the `NgZone` instance for the application. In the future, this provider
will be used for applications to specifically opt-in to change detection
powered by ZoneJS rather than it being provided by default.
This API does _not_ specifically provide support for developers to define their own
`NgZone` implementation or opt in to `NoopNgZone` directly. Both of
these are possible today, but are effectively unsupported (applications
that use these are left to their own devices to run change detection at
the appropriate times). That said, developers can still use DI in
`bootstrapApplication` to provide an `NgZone` implementation instead,
it's just not specifically available in the
`provideZoneChangeDetection` function.
PR Close#49557
This commit updates the `bootstrapApplication` method to get the
`NgZone` instance from DI. This will allow a future change to enable
developers to configure `NgZone` in DI rather than adding the options to
the top level like in `bootstrapModuleFactory` (which is done in order
to get the NgZone instance without going through DI).
PR Close#49557
This commit removes a code that increments the `rendererCreateComment` counter unnecessarily. The counter gets incemented even in hydration scenarios where we do not create a comment node. The counter still gets incemented in the right locations (when we *actually* create a node).
PR Close#49656
* Prevent reads of signals during the notification process. This shouldn't
ever be triggered by user code but is more of a preventative for
internal misuse. Reading a signal during notification would/could create
glitches where the values being read are not updated to reflect the
values being updated by the notification.
* Prevent signal writes inside of computed's. These are meant to be
derived values and should not have any side-effects like writing new
values to other signals
* Prevent signal writes inside of effects by default. Writing to signal
values during the execution of an effect can lead to the
`ExpressionChangedAfterItHasBeenCheckedError` if writing to signals
that represent global state which is read in a parent component. This is
mostly just a problem for `OnPush`/`CheckAlways` components, but with
signals being new and pure signal components not even available yet,
it will be the majority for a long time.
PR Close#49631
This commit adds the basic sketch for the implementation of `fromObservable`
and `fromSignal`, the two basic primitives which form the RxJS interop layer
with signals.
PR Close#49154
We've been experimenting with the DeepReadonly type that would make
signal values deeply read-only and prevent accidental changes without
going to the owner of data. What we've found out during the experiments
is that additional safety net has more drawbacks than benefits: it just
introduces too much friction to be practical for daily usage.
PR Close#49154
This commit adds a logic to output basic hydration stats into a console. This is also helpful to ensure that hydration is enabled and works.
PR Close#49617
This commit adds a new metric into the `ngDevMode` to count a number of components that skipped hydration (where `ngSkipHydration` attribute was applied).
PR Close#49617
This commit updates the `effect` primitive and significantly changes the
timing of effect execution.
Previously, effects were scheduled via the microtask queue. This commit
changes effects to run throughout the change detection process instead.
Running effects this way avoids needing additional rounds of change
detection to resolve effects, with the tradeoff that they're harder to use
for model-to-model synchronization (which can be seen as a good thing).
PR Close#49641
This commit consolidates the `RendererFactory` and `Sanitizer` properties
of `LView` onto a single object, the `LViewEnvironment`. These properties
are both set from DI when the root view is created, and not overridden when
child views are created (but inherited from the parent view).
This is a precursor commit to adding the `EffectManager` into the
`LViewEnvironment`.
PR Close#49641
This change extends the effect API surface so effects can, optionally,
return a cleanup function. Such function, if returned, is executed
prior to the subsequent effect run.
PR Close#49625
This commits adds `makeStateKey`, `StateKey` and `TransferState` methods in `@angular/core` as public API and deprecated the same exported symbols in `@angular/platform-browser`.
DEPRECATED: `makeStateKey`, `StateKey` and `TransferState` exports have been moved from `@angular/platform-browser` to `@angular/core`. Please update the imports.
```diff
- import {makeStateKey, StateKey, TransferState} from '@angular/platform-browser';
+ import {makeStateKey, StateKey, TransferState} from '@angular/core';
```
PR Close#49563
Signal functions are marked with a `[SIGNAL]` symbol property, which was
previously set to `true`.
This commit changes the `[SIGNAL]` property to have the `ReactiveNode` as
its value instead. This doesn't change the behavior of the signal library
itself, but exposes the signal internals in a way where developer tooling
can look at any signal and interact with its dependency graph.
PR Close#49529
Previously the signals implementation maintained separate interfaces for
`Producer` and `Consumer` nodes, with implementers choosing to implement
one or both interfaces. Operations defined against those interfaces were
exposed as importable functions to be called with the object implementing
the relevant contract as the first argument.
This commit refactors the implementation to merge both abstractions into a
single `ReactiveNode` base class, which represents both producers and
consumers in the graph. Implementers choose to interact with a subset of the
`ReactiveNode` API depending on their role in the graph. Operations are now
available as protected methods on the base class, instead of separate
functions.
PR Close#49529
Previously, effects were queued in the global microtask queue and executed
directly. This had an undesired consequence: whichever effect scheduled
first determined the zone in which all other effects would run, *and* that
zone depended on where the signal happened to be set which triggered that
first effect. This behavior would be extremely unpredictable.
This commit adds zone awareness to the effect API. effects now capture the
current zone when they're created, and this zone is used to run the effect
callback regardless of which zone set the signal.
PR Close#49529
This commit adds a `DeepReadonly` type to the signals API, and makes signal
getters return an immutable version of their value type. This doesn't
prevent all mutation but adds some friction against modifying the values
within signals outside of the proper mutation APIs.
PR Close#49529
The `effect` implemented in the signal library is useful for testing but
does not integrate with Angular. This commit moves that code to the
actual framework package and integrates it with automatic cleanup via
`DestroyRef`. A simpler effect implementation is used in the signal tests to
test the `Watch` primitive.
Further commits will update the scheduling to tie effects together with
change detection.
PR Close#49529
This commit switches the `signal` and `computed` APIs to accept an optional
options argument as their second argument, instead of an equality function
directly. The equality function has moved to an option in the options
argument.
PR Close#49529
This commit renames the `SettableSignal` interface to align with recent
naming changes. `WritableSignal` is considered a more suitable name since
it supports more mutation operations than just directly setting.
PR Close#49529
This commit adds an assertion function to the public API, which allows
authors of functions which rely on `inject` to validate that they're being
called with the right context. This mostly produces a nicer error message
than calling `inject()` and relying on Angular's default error message for
that.
PR Close#49529
This fixes two cases where DOM node navigation during hydration would be broken. It also fixes an infinite loop on clearing DOM during skip hydration blocks
PR Close#49615
This commit implements a simple tracker of the pending tasks during initial rendering. The class allows adding and removing tasks from the set. The class also exposes a promise that gets resolved once the last task is removed.
This tracker is needed to keep track of ongoing processes like Router navigation (and potentially HTTP requests) and acts as a signaling mechanism to SSR and hydration that the application is in the "stable" state and a serialization can be performed.
This class would also act as a future replacement for the `ApplicationRef.isStable` for zoneless applications.
PR Close#49576
`ComponentRef.setInput` currently sets the input on the component regardless
of the previous value the method was called with. This results in
different behavior from bindings in templates, which only set inputs
when the value differs in the `Object.is` check from its previous value.
BREAKING CHANGE: ComponentRef.setInput will only set the input on the
component if it is different from the previous value (based on `Object.is`
equality). If code relies on the input always being set, it should be
updated to copy objects or wrap primitives in order to ensure the input
value differs from the previous call to `setInput`.
PR Close#49607
Currently when the value of a styling property that has a unit is empty string a invalid value is generated.
Example:
`[style.width.px] = ""` will generate a value of `"px"`, when instead it should be `""`.
This causes browser to reset the value to an empty string. This is however not the case in Domino with changes in https://github.com/angular/domino/commit/bfc9114d1eb5b7591c43a7c6aef6ad50d24e369f.
This commit fixes the issues and generate correct values.
PR Close#49460
This commit updates the serialization logic to avoid serializing a path for a node that was content projected (based on template information), but is not present in the DOM. This can happen if a <ng-content> is used with the *ngIf="false", for example: `<ng-content *ngIf="false" />`.
PR Close#49590
This commit updates the `LView` in Angular to be a `Consumer` of
signals. If a signal is read when executing a template, it marks the
view dirty. In addition, if a signal is read when executing host
bindings, it also marks views dirty.
One interesting thing about signal reads in host bindings
is that they perform a bit better than what we can do with today's
APIs. In order to re-execute host bindings for an `OnPush` component that
might have changed, you would probably inject `ChangeDetectorRef` and call
`markForCheck`. This will mark the _current component_ and parents
dirty. However, host bindings are executed as part of refreshing the
_parent_ so there is really no need to re-execute the current component
if the only thing that changed is the host bindings. When a signal is
read in host bindings, it marks the parent dirty and not the component
that defined the host binding.
Additionally, this commit avoids allocating a full consumer for each
`LView` by re-using a consumer until template execution results in a
signal read. At this point, we assign that consumer to the `LView` and
create a new consumer to "tentatively" use for the future `LView`
template executions.
Co-authored-by: Dylan Hunn <github@dylanhunn.com>
PR Close#49153