npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill angular-ssr深度知识:使用
mcp__documentation__fetch_docs,技术参数设为angular,主题设为ssr以获取完整文档。
# 向现有项目添加 SSR
ng add @angular/ssr
此命令会创建:
server.ts - Express 服务器入口点src/app/app.config.server.ts - 服务器端特定提供程序angular.json 以包含服务器构建器// 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);
Deep Knowledge : Use
mcp__documentation__fetch_docswith technology:angular, topic:ssrfor comprehensive documentation.
# Add SSR to existing project
ng add @angular/ssr
This creates:
server.ts - Express server entry pointsrc/app/app.config.server.ts - Server-specific providersangular.json with server builder// 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);
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
// 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
];
// app.config.ts - 使用 @angular/ssr 时,水合默认启用
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(), // 自动包含
]
};
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();
});
}
}
| 反模式 | 为何不好 | 正确方法 |
|---|---|---|
直接访问 window/document | 破坏 SSR | 使用 isPlatformBrowser() |
| 未启用水合 | 整个页面重新渲染 | 启用 provideClientHydration() |
| 对仅限认证的页面使用 SSR | 浪费服务器资源 | 使用 RenderMode.Client |
| 忽略传输状态 | 重复数据获取 | 水合会自动处理此问题 |
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 水合不匹配 | 水合前 DOM 已改变 | 避免在 ngOnInit 中操作 DOM |
window is not defined | 服务器端访问 | 使用 isPlatformBrowser() 进行防护 |
| SSR 速度慢 | 计算量过大 | 使用 @defer 移至客户端 |
| SEO 不生效 | 仅客户端渲染 | 使用 RenderMode.Server 或 Prerender |
每周安装量
1
仓库
首次出现
3 天前
安全审计
安装于
amp1
cline1
openclaw1
opencode1
cursor1
kimi-cli1
// 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
];
// app.config.ts - Hydration is enabled by default with @angular/ssr
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(), // Included automatically
]
};
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();
});
}
}
| Anti-Pattern | Why It's Bad | Correct Approach |
|---|---|---|
Direct window/document access | Breaks SSR | Use isPlatformBrowser() |
| No hydration | Full page re-render | Enable provideClientHydration() |
| SSR for auth-only pages | Wasted server resources | Use RenderMode.Client |
| Ignoring transfer state | Double data fetch | Hydration handles this automatically |
| Issue | Likely Cause | Solution |
|---|---|---|
| Hydration mismatch | DOM changed before hydration | Avoid DOM manipulation in ngOnInit |
window is not defined | Server-side access | Guard with isPlatformBrowser() |
| Slow SSR | Heavy computation | Move to client with @defer |
| SEO not working | Client-only rendering | Use RenderMode.Server or Prerender |
Weekly Installs
1
Repository
First Seen
3 days ago
Security Audits
Installed on
amp1
cline1
openclaw1
opencode1
cursor1
kimi-cli1
Schema标记专家指南:结构化数据实现与SEO优化,提升富媒体搜索结果
29,200 周安装