What is server-side rendering lifecycle in Angular Universal?
Angular Universal enables Server-Side Rendering (SSR) for Angular applications, improving initial load performance, SEO, and user experience. The SSR lifecycle involves several critical steps, from the server receiving a request to the client hydrating the application.
1. Request Reception and Server Initialization
The lifecycle begins when a user's browser sends an HTTP request to the server. Instead of serving an empty HTML shell, the Node.js server (typically running Express) intercepts this request.
The server then bootstraps the Angular application using the AppServerModule, which is specifically designed for the server environment. This module typically imports AppModule from the main application, but provides server-specific providers.
2. Server-Side Rendering Process
Once bootstrapped, Angular renders the application's components on the server. During this phase, key lifecycle hooks like ngOnInit and ngOnChanges are executed, just as they would be on the client-side. However, certain client-side specific APIs (e.g., window, document) are not available directly or are shims provided by Angular Universal.
Data Fetching Considerations
Any data fetching (e.g., HttpClient requests to an API) must complete synchronously for the server render to be complete. If data fetching is asynchronous and not awaited, the server will send a partially rendered page without the necessary data.
Proper use of Promises or Observables that complete within the server's render time is crucial. The HttpClient works seamlessly on both server and client, making API calls from the Node.js environment during SSR.
import { Injectable, PLATFORM_ID, Inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { isPlatformBrowser } from '@angular/common';
import { Observable } from 'rxjs';
interface Post {
id: number;
title: string;
body: string;
}
@Injectable({ providedIn: 'root' })
export class DataService {
constructor(
private http: HttpClient,
@Inject(PLATFORM_ID) private platformId: Object
) {}
getPosts(): Observable<Post[]> {
// Conditional logic for platform can be useful but HttpClient
// often handles server/browser differences transparently.
if (isPlatformBrowser(this.platformId)) {
// Client-side specific logic if needed, e.g., using localStorage
}
// This call works identically on server and client
return this.http.get<Post[]>('https://jsonplaceholder.typicode.com/posts');
}
}
3. State Transfer (TransferState)
To prevent the client-side application from refetching data that was already fetched during SSR, Angular Universal uses the TransferState service. This service allows you to store application state (like fetched API data) on the server-side.
The stored state is then serialized and embedded into the HTML response, typically as a JSON script tag within the head or body. This ensures that when the client-side application bootstraps, it can retrieve this state and avoid redundant data requests, leading to a faster and smoother user experience.
4. HTML Generation and Response
Once the server-side rendering is complete and all asynchronous operations (like data fetching) have resolved, Angular serializes the fully rendered application's DOM into a static HTML string.
The Node.js server then sends this generated HTML, along with the embedded TransferState data, as the HTTP response to the client's browser. This is the first content the user sees, leading to improved perceived performance.
5. Client-Side Hydration
Upon receiving the HTML, the browser displays the static content immediately. In the background, Angular's client-side application bundle is downloaded and bootstrapped.
This process, known as hydration, involves Angular re-rendering the application on the client-side. Instead of rebuilding the DOM from scratch, it detects and reuses the existing server-rendered DOM elements. It then restores the application state using the TransferState data and attaches event listeners to make the application fully interactive. This seamless transition provides the best of both SSR and SPA worlds.