By leveraging deferrable views, or defer blocks, developers can control when and how different parts of the application become interactive (hydrated). This approach allows content to be incrementally hydrated based on user actions, visibility, or specific conditions, such as hydrate on, hydrate when, or hydrate never.
In modern web applications, optimizing performance and user experience is essential, especially when dealing with large-scale, dynamic content. Angular introduces incremental hydration as a solution to improve page interactivity and load times. By leveraging deferrable views, or defer blocks, developers can control when and how different parts of the application become interactive (hydrated). This approach allows content to be incrementally hydrated based on user actions, visibility, or specific conditions, such as hydrate on, hydrate when, or hydrate never.
Hydration in Angular:
Hydration is the process of re-establishing a server-side rendered application on the client. It involves tasks such as reusing the DOM elements generated by the server, maintaining the application’s state, transferring data that the server has already retrieved, and other related operations.
If you’ve utilized Angular CLI to activate server-side rendering (SSR), either during the application’s initial setup or later by running ng add @angular/ssr
, the code necessary for enabling hydration will already be integrated into your application.
ng add @angular/ssr
this is how your app.config looks like:
import {
bootstrapApplication,
provideClientHydration,
} from '@angular/platform-browser';
...
bootstrapApplication(AppComponent, {
providers: [provideClientHydration()]
});
How to check Hydration is Enabled?
When running an application in development mode, you can verify that hydration is enabled by opening the Developer Tools in your browser and checking the console. There, you should see a message displaying hydration-related statistics, such as the number of components and nodes that have been hydrated. Angular computes these statistics based on all components rendered on the page, including those from third-party libraries.
How to Allow users to interact even before Hydration accomplishes?
When an application is rendered on the server, the produced HTML becomes visible in the browser as soon as it loads. Users might think they can interact with the page right away, but event listeners are not attached until the hydration process is finished. Starting from version 18, you can enable the Event Replay feature, which captures all events that occur before hydration and replays them once hydration is complete. You can activate this feature using the withEventReplay() function. For example:
import {provideClientHydration, withEventReplay} from '@angular/platform-browser';
...
bootstrapApplication(App, {
providers: [
provideClientHydration(withEventReplay())
]
});
How to Disable Hydration for Specific Components?
Certain components might not function correctly with hydration enabled due to issues like direct DOM manipulation. As a workaround, you can add the ngSkipHydration attribute to a component's tag to bypass the hydration process for that entire component.
<app-example ngSkipHydration />
OR
@Component({
...
host: {ngSkipHydration: 'true'},
})
class UserProjectsComponent {}
Configuration — Incremental Hydration:
Defines a configuration object, appConfig, for an Angular application using incremental hydration. The ApplicationConfig object includes a providers array, which registers services or functionalities available throughout the app.
In this case, the code adds client-side hydration capabilities by using provideClientHydration, along with the withPartialHydration() option. Here's a breakdown:
provideClientHydration(): This function enables client-side hydration in the application. Hydration refers to the process of converting static content (typically generated during server-side rendering) into fully interactive, dynamic content once the client-side JavaScript is loaded.
withPartialHydration(): This option enables partial hydration, allowing specific parts of the application to be hydrated incrementally rather than hydrating the entire page all at once. It optimizes performance by only hydrating necessary portions of the app based on user interaction or predefined conditions.
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(withPartialHydration())
]
};
Incremental Hydration in Action:
Deferrable views, also known as defer blocks, serve as the foundational unit and boundary for incremental hydration in Angular.
A defer block defines an incremental hydration boundary by applying conditions such as hydrate on, hydrate when, or hydrate never. It supports idle, viewport and interaction.
For example:
<user-detail />
@defer (on immediate; hydrate on interaction) {
<deferred-user-projects />
<deferred-user-blogs />
}
Nested Hydration:
When multiple @defer blocks are in a dehydrated state, their conditions are evaluated concurrently. For instance, in the following structure:
@defer (hydrate on hover) {
@defer (hydrate on timer(15s)) {
...
}
}
The outer block “hydrate on hover” will hydrate if the mouse is hovered over any of the content inside of it. Even if the block is never hovered, the inner block’s “hydrate on timer(15s)” timer will trigger hydration after 15 seconds.
Hydrate with never trigger:
The @defer (hydrate never) trigger in Angular defines a defer block that will never be hydrated, meaning the content inside the block remains static and non-interactive.
@defer (hydrate never) {
<user-projects />
}
- The component will be rendered but will not be hydrated.
- It means that even if the application is fully loaded on the client-side, the content inside this defer block will stay static and will not become interactive.
This is useful for scenarios where certain parts of the application do not require interactivity or should remain in a static state to save resources.
Reference:
Angular RFC: https://github.com/angular/angular/discussions/57664
Angular Source PR: https://github.com/angular/angular/pull/58193