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
References: SSR GuideHydration@angular/ssr
版本: Angular 21 (2025) 标签: SSR, Hydration, 预渲染, SEO, Angular Universal
参考资料: SSR指南Hydration@angular/ssr

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:
    provideClientHydration
    — Modern hydration setup with event replay
  • NEW: Deferrable views (@defer) — Load components lazily with SSR support
  • NEW:
    ngSkipHydration
    — Opt-out of hydration for specific components
  • DEPRECATED: Angular Universal — Migrate to @angular/ssr
本部分记录了近期版本对应的API变动:
  • 新增:增量Hydration —— 增量式水合组件,而非一次性完成全部组件水合 来源
  • 新增:混合渲染 —— 支持按路由配置渲染模式 来源
  • 新增:
    provideClientHydration
    —— 带事件重放功能的现代化水合配置方案
  • 新增:可延迟视图(@defer)—— 支持SSR的组件懒加载能力
  • 新增:
    ngSkipHydration
    —— 可为指定组件关闭水合功能
  • 已废弃:Angular Universal —— 请迁移至@angular/ssr

Best Practices

最佳实践

  • Enable SSR with CLI
bash
ng add @angular/ssr
  • 通过CLI开启SSR
bash
ng add @angular/ssr

Or 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)) {
    // 仅在服务端执行的代码
  }
}