angular-ssr
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese@angular/ssr (Server-Side Rendering)
@angular/ssr (服务端渲染)
Version: Angular 21 (2025)
Tags: SSR, Hydration, Prerendering, SEO, Angular Universal
版本: Angular 21 (2025)
标签: SSR, Hydration, 预渲染, SEO, Angular Universal
API Changes
API变更
This section documents recent version-specific API changes.
-
NEW: Incremental Hydration — Hydrate components incrementally instead of all at once source
-
NEW: Hybrid Rendering — Per-route rendering mode configuration source
-
NEW:— Modern hydration setup with event replay
provideClientHydration -
NEW: Deferrable views (@defer) — Load components lazily with SSR support
-
NEW:— Opt-out of hydration for specific components
ngSkipHydration -
DEPRECATED: Angular Universal — Migrate to @angular/ssr
Best Practices
最佳实践
- Enable SSR with CLI
bash
ng add @angular/ssr- 通过CLI开启SSR
bash
ng add @angular/ssrOr create new project with SSR
或者创建支持SSR的新项目
ng new my-app --ssr
- Enable client hydration
```ts
import { provideClientHydration } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration()
]
};- Use incremental hydration for better performance
ts
import { provideClientHydration, withIncrementalHydration } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(withIncrementalHydration())
]
};- Use @defer for lazy loading
ts
@Component({
template: `
@defer (on viewport) {
<heavy-component />
} @placeholder {
<div>Loading...</div>
}
`
})
export class MainComponent {}- Handle browser-specific code with isPlatformBrowser
ts
import { PLATFORM_ID, Inject } from '@angular/core';
constructor(@Inject(PLATFORM_ID) private platformId: Object) {
if (isPlatformBrowser(this.platformId)) {
// Browser-only code
}
}- Use TransferState to prevent duplicate HTTP requests
ts
import { TransferState, makeStateKey } from '@angular/platform-browser';
@Injectable()
export class DataService {
constructor(private http: HttpClient, private transferState: TransferState) {}
getData() {
const DATA_KEY = makeStateKey('DATA');
if (this.transferState.hasKey(DATA_KEY)) {
return of(this.transferState.get(DATA_KEY, []));
}
return this.http.get('/api/data').pipe(
tap(data => this.transferState.set(DATA_KEY, data))
);
}
}- Skip hydration for DOM-manipulating components
ts
@Component({
selector: 'app-third-party',
host: {
'ngSkipHydration': 'true'
}
})
export class ThirdPartyComponent {}- Configure hybrid rendering per route
ts
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{
path: 'dashboard',
renderMode: RenderMode.Client
},
{
path: 'blog/:slug',
renderMode: RenderMode.Server
},
{
path: 'about',
renderMode: RenderMode.Prerender
}
];- Use platform-server for server-side logic
ts
import { isPlatformServer } from '@angular/common';
constructor(@Inject(PLATFORM_ID) platformId: Object) {
if (isPlatformServer(platformId)) {
// Server-side only
}
}ng new my-app --ssr
- 开启客户端水合
```ts
import { provideClientHydration } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration()
]
};- 使用增量Hydration优化性能
ts
import { provideClientHydration, withIncrementalHydration } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(withIncrementalHydration())
]
};- 使用@defer实现懒加载
ts
@Component({
template: `
@defer (on viewport) {
<heavy-component />
} @placeholder {
<div>Loading...</div>
}
`
})
export class MainComponent {}- 通过isPlatformBrowser处理仅在浏览器端运行的代码
ts
import { PLATFORM_ID, Inject } from '@angular/core';
constructor(@Inject(PLATFORM_ID) private platformId: Object) {
if (isPlatformBrowser(this.platformId)) {
// 仅在浏览器端执行的代码
}
}- 使用TransferState避免重复发起HTTP请求
ts
import { TransferState, makeStateKey } from '@angular/platform-browser';
@Injectable()
export class DataService {
constructor(private http: HttpClient, private transferState: TransferState) {}
getData() {
const DATA_KEY = makeStateKey('DATA');
if (this.transferState.hasKey(DATA_KEY)) {
return of(this.transferState.get(DATA_KEY, []));
}
return this.http.get('/api/data').pipe(
tap(data => this.transferState.set(DATA_KEY, data))
);
}
}- 对操作DOM的组件跳过水合
ts
@Component({
selector: 'app-third-party',
host: {
'ngSkipHydration': 'true'
}
})
export class ThirdPartyComponent {}- 按路由配置混合渲染模式
ts
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{
path: 'dashboard',
renderMode: RenderMode.Client
},
{
path: 'blog/:slug',
renderMode: RenderMode.Server
},
{
path: 'about',
renderMode: RenderMode.Prerender
}
];- 使用platform-server处理服务端逻辑
ts
import { isPlatformServer } from '@angular/common';
constructor(@Inject(PLATFORM_ID) platformId: Object) {
if (isPlatformServer(platformId)) {
// 仅在服务端执行的代码
}
}