
Angular 17 原生支持静态预渲染(SSG),通过 @angular/ssr 包在构建时生成带完整 HTML 结构的静态页面;但若路由配置不匹配或数据未正确注入,预渲染内容将仅保留骨架 DOM,真实数据仍需客户端 hydration 加载。
angular 17 原生支持静态预渲染(ssg),通过 `@angular/ssr` 包在构建时生成带完整 html 结构的静态页面;但若路由配置不匹配或数据未正确注入,预渲染内容将仅保留骨架 dom,真实数据仍需客户端 hydration 加载。
Angular 17 标志性地引入了全新的 @angular/ssr 包,取代了旧版 Angular Universal 的复杂配置,使预渲染(Prerendering)真正成为开箱即用的一等公民。与服务器端渲染(SSR)不同,预渲染是在构建阶段(build time) 针对指定路由生成完全静态的 HTML 文件(如 dist/ssr/browser/products/bronco/index.html),适用于内容相对稳定、SEO 敏感的页面(如产品详情页、博客文章等)。
你观察到的 index.html 中 <app-root></app-root> 内容为空、仅含占位结构和 <script id="ng-state">{"__nghData__": [...]}</script>,这并非异常——而是 Angular 17 预渲染的典型行为:它确实已执行了组件树渲染和初始数据获取(如 resolve 或 loader 中的逻辑),并将序列化状态写入 ng-state 脚本块;但为保障 Hydration 一致性与安全性,实际 DOM 渲染结果默认被剥离,仅保留 hydration 所需的最小骨架。真正的“可见内容”会在浏览器加载 main-*.js 后,由 Angular 的水合(Hydration)机制基于 ng-state 中的数据重新激活并填充 DOM。
⚠️ 然而,你遇到的 /product/bronco 页面无数据,核心原因正如答案所指出:路由定义与请求路径不匹配。
你的预渲染目标是 /products/bronco(复数形式),但 Angular Router 配置却是 product/:id(单数)。由于预渲染器严格依据 routes 配置启动独立的无头浏览器实例访问对应 URL,若该 URL 无法被 Router 正确识别为有效路由,则组件不会被激活,resolver 不会执行,ng-state 中自然为空 —— 这正是你看到 "__nghData__":[{"c":{"0":[]}}] 的根本原因。
✅ 正确做法如下:
-
统一路由定义(确保
app-routing.module.ts中):const routes: Routes = [ { path: 'products/:id', component: ProductDetailComponent, resolve: { product: ProductResolver } }, // 注意:此处必须与 prerender 配置中的路径完全一致 ]; -
在
angular.json中精准配置预渲染路由:"prerender": { "builder": "@angular/ssr:prerender", "options": { "routes": ["/", "/products/bronco", "/products/mustang"] } } -
运行预渲染命令:
ng run your-app:prerender
生成的文件将位于
dist/your-app/browser/products/bronco/index.html,此时打开该文件,应能看到已渲染出的产品标题、描述等真实内容(而非空<router-outlet></router-outlet>)。
? 补充说明:Angular 17 的预渲染默认启用 static 模式(即 SSG),若需动态数据支持(如 CMS 实时内容),可结合 ssg loader 的 params 或自定义 routeHandler 实现参数化预渲染;同时务必检查 ProductResolver 是否返回 Observable 或 Promise,且不依赖浏览器专属 API(如 window、localStorage),否则构建时将报错。
总结:预渲染 ≠ 客户端渲染的截图,而是服务端(构建时)的 Angular 应用实例化 + 数据解析 + 状态序列化。验证成功与否,关键看三点:① 路由路径严格匹配;② Resolver/Loader 同步或异步返回有效数据;③ 构建输出目录中对应 HTML 文件是否包含预期文本内容(而非仅骨架)。一旦满足,即可获得零 JavaScript 依赖的首屏 HTML,显著提升 LCP 与 SEO 表现。










