angular-ssr
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAngular SSR - Quick Reference
Angular SSR - 快速参考
Deep Knowledge: Usewith technology:mcp__documentation__fetch_docs, topic:angularfor comprehensive documentation.ssr
深度文档:使用工具,指定technology为mcp__documentation__fetch_docs、topic为angular可获取完整文档。ssr
Setup
配置
bash
undefinedbash
undefinedAdd SSR to existing project
为现有项目添加SSR
ng add @angular/ssr
This creates:
- `server.ts` - Express server entry point
- `src/app/app.config.server.ts` - Server-specific providers
- Updates `angular.json` with server builderng add @angular/ssr
此命令会创建:
- `server.ts` - Express服务器入口文件
- `src/app/app.config.server.ts` - 服务器专属提供者配置
- 更新`angular.json`中的服务器构建器配置Server Configuration
服务器配置
typescript
// app.config.server.ts
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';
import { provideServerRoutesConfig } from '@angular/ssr';
import { appConfig } from './app.config';
import { serverRoutes } from './app.routes.server';
const serverConfig: ApplicationConfig = {
providers: [
provideServerRendering(),
provideServerRoutesConfig(serverRoutes),
]
};
export const config = mergeApplicationConfig(appConfig, serverConfig);typescript
// app.config.server.ts
import { mergeApplicationConfig, ApplicationConfig } from '@angular/core';
import { provideServerRendering } from '@angular/platform-server';
import { provideServerRoutesConfig } from '@angular/ssr';
import { appConfig } from './app.config';
import { serverRoutes } from './app.routes.server';
const serverConfig: ApplicationConfig = {
providers: [
provideServerRendering(),
provideServerRoutesConfig(serverRoutes),
]
};
export const config = mergeApplicationConfig(appConfig, serverConfig);Route-Level Rendering Modes
路由级渲染模式
typescript
// app.routes.server.ts
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{ path: '', renderMode: RenderMode.Prerender }, // Static at build time
{ path: 'dashboard', renderMode: RenderMode.Server }, // SSR per request
{ path: 'profile/**', renderMode: RenderMode.Client }, // Client-only (SPA)
{ path: '**', renderMode: RenderMode.Server }, // Default: SSR
];typescript
// app.routes.server.ts
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{ path: '', renderMode: RenderMode.Prerender }, // 构建时静态预渲染
{ path: 'dashboard', renderMode: RenderMode.Server }, // 每次请求触发SSR
{ path: 'profile/**', renderMode: RenderMode.Client }, // 仅客户端渲染(SPA模式)
{ path: '**', renderMode: RenderMode.Server }, // 默认:SSR
];Hydration
Hydration(水合)
typescript
// app.config.ts - Hydration is enabled by default with @angular/ssr
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(), // Included automatically
]
};typescript
// app.config.ts - 使用@angular/ssr时默认启用Hydration
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(), // 自动包含
]
};Platform Checks
平台检测
typescript
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
import { PLATFORM_ID, inject } from '@angular/core';
@Component({ ... })
export class MyComponent {
private platformId = inject(PLATFORM_ID);
ngOnInit() {
if (isPlatformBrowser(this.platformId)) {
// Browser-only code (localStorage, window, DOM manipulation)
window.addEventListener('scroll', this.onScroll);
}
}
}
// Or use afterNextRender for one-time browser init
import { afterNextRender } from '@angular/core';
@Component({ ... })
export class ChartComponent {
constructor() {
afterNextRender(() => {
// Runs only in browser after first render
this.initChart();
});
}
}typescript
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
import { PLATFORM_ID, inject } from '@angular/core';
@Component({ ... })
export class MyComponent {
private platformId = inject(PLATFORM_ID);
ngOnInit() {
if (isPlatformBrowser(this.platformId)) {
// 仅浏览器端执行的代码(localStorage、window、DOM操作)
window.addEventListener('scroll', this.onScroll);
}
}
}
// 或使用afterNextRender进行一次性浏览器初始化
import { afterNextRender } from '@angular/core';
@Component({ ... })
export class ChartComponent {
constructor() {
afterNextRender(() => {
// 仅在浏览器端首次渲染后执行
this.initChart();
});
}
}Anti-Patterns
反模式
| Anti-Pattern | Why It's Bad | Correct Approach |
|---|---|---|
Direct | Breaks SSR | Use |
| No hydration | Full page re-render | Enable |
| SSR for auth-only pages | Wasted server resources | Use |
| Ignoring transfer state | Double data fetch | Hydration handles this automatically |
| 反模式 | 危害 | 正确做法 |
|---|---|---|
直接访问 | 破坏SSR渲染 | 使用 |
| 未启用Hydration | 页面完全重渲染 | 启用 |
| 对仅需授权的页面使用SSR | 浪费服务器资源 | 使用 |
| 忽略状态传递 | 重复数据请求 | Hydration会自动处理此问题 |
Quick Troubleshooting
快速故障排除
| Issue | Likely Cause | Solution |
|---|---|---|
| Hydration mismatch | DOM changed before hydration | Avoid DOM manipulation in |
| Server-side access | Guard with |
| Slow SSR | Heavy computation | Move to client with |
| SEO not working | Client-only rendering | Use |
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| Hydration不匹配 | 水合前DOM已被修改 | 避免在 |
| 在服务器端访问了window对象 | 使用 |
| SSR速度慢 | 存在大量计算逻辑 | 使用 |
| SEO不生效 | 使用了仅客户端渲染 | 使用 |