Angular v9 和 Universal:开箱即用的 SSR 和预渲染!

2025-06-04

Angular v9 和 Universal:开箱即用的 SSR 和预渲染!

最初于 2020 年 1 月 5 日发布于https://samvloeberghs.be

目标受众

本文和指南旨在帮助所有使用 Angular v9 的用户开始使用服务器端渲染 (SSR) 并预渲染其应用程序。请注意,这些说明仅适用于使用 Angular v9 的新应用或更新的应用。要使 Angular v2-v8 获得相同的效果,需要进行更多自定义设置。

示例项目

对于示例项目,我们使用一个启用了路由的、由 angular-cli 生成的最小项目。此外,还生成了 home( /) 和 about( ) 路由及其组件。通过使用惰性加载的新闻模块,还配置了/about额外的动态 overview( /news) 和 newsdetail( ) 路由。/news/:id

此概述和详细信息页面的数据是我们从静态资产文件夹(/assets/news.json)加载的简单 JSON 数据对象,如下所示:

// /assets/news.json
[
  {
    "id": 1,
    "title": "Newsitem #1",
    "short": "Lorem ipsum dolor sit amet, ...",
  },
  {
    "id": 2,
    "title": "Newsitem #2",
    "short": "Lorem ipsum dolor sit amet, ..."
  }
]

以下动画展示了我们的应用程序如何使用路由和加载动态数据。此基本示例应用程序的完整源代码可在此处找到

应用动画示例

向您的应用程序添加服务器端渲染(SSR)

通常情况下,你的 Angular 应用只会在浏览器加载后立即渲染。在这种情况下,Web 服务器的唯一职责就是提供 Angular 应用的静态文件(构建成功后 dist 文件夹中的所有内容)。

使用 SSR,应用程序的特定路由(例如/about)将完全在服务器上渲染,就像在浏览器中渲染一样。这使得像 Google 这样的搜索引擎和像 Facebook 这样的社交媒体平台能够索引并显示应用程序页面的预览,因为完整的 HTML 内容从服务器初始加载时即可获取,而无需 JavaScript。

入门

首先,您需要做的就是@nguniversal/express-engine使用 angular-cli 添加包:

ng add @nguniversal/express-engine@next
# as soon as v9 is released you can drop the "@next"

ng add命令通过添加必要的文件和更新angular.json配置文件来更新您的应用程序。架构部分新增了 3 个配置:serverserve-ssrprerender。这 3 个配置各有用途,它们共同帮助我们实现所需的结果。让我们来看看这些变化。

// updated angular.json
{
    "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
    "version": 1,
    "newProjectRoot": "projects",
    "projects": {
    "ng-v9-universal": {
      "..": "..",
      "architect": {
        "..": "..",
        "server": {
          "builder": "@angular-devkit/build-angular:server",
          "options": {
            "outputPath": "dist/ng-v9-universal/server",
            "main": "server.ts",
            "tsConfig": "tsconfig.server.json"
          },
          "configurations": {
            "production": {
              "..": ".."
            }
          }
        },
        "serve-ssr": {
          "builder": "@nguniversal/builders:ssr-dev-server",
          "options": {
            "browserTarget": "ng-v9-universal:build",
            "serverTarget": "ng-v9-universal:server"
          },
          "configurations": {
            "production": {
              "browserTarget": "ng-v9-universal:build:production",
              "serverTarget": "ng-v9-universal:server:production"
            }
          }
        },
        "prerender": {
          "builder": "@nguniversal/builders:prerender",
          "options": {
            "browserTarget": "ng-v9-universal:build:production",
            "serverTarget": "ng-v9-universal:server:production",
            "routes": []
          },
          "configurations": {
            "production": {}
          }
        }
      }
    }
  }
  "..": ".."
}

server运行选项

在你的系统(或后端)上运行 Angular 构建需要服务器,因此该server.ts文件会被添加到项目的根目录。这个 TypeScript 文件包含渲染路由和提供应用程序静态资源所需的所有设置。如第 13-15 行所示,它定义了此服务器的输出路径,以及一个tsConfig定义如何构建服务器 TypeScript 代码的变量。与构建一样,browser我们也可以定义特定于生产环境的环境变量。

构建此服务器与构建 Angular 应用程序一样简单。只需在终端中运行以下命令,服务器就会构建到dist/ng-v9-universal/server

npm run build:ssr

serve-ssr运行选项

在开发应用程序时,您可能只需运行ng serve。此命令将为您设置一个开发服务器,该服务器具有热重载功能以及其他所有功能,可为您提供良好的开发体验。

测试服务器端渲染部分也可以在开发过程中进行。只需以 运行应用程序,ng run ng-v9-universal:serve-ssr服务器源文件就会与应用程序源文件一起被监视。由于实时重载,更改应用程序或服务器的代码将自动重新启动应用程序。

现在,如果您重新加载任何页面,例如新闻概览(/news),初始有效负载将包含新闻概览的完整呈现 HTML,包括动态数据。

SSR动画

prerender运行选项

最后一项新增功能是可以预渲染应用程序的路由。为了实现此功能,预渲染构建器会使用(由@mgechevguess-parser构建)来猜测静态路由。它会分析应用程序的路由模块,并对找到的路由进行预渲染。

要预渲染应用程序的路由,只需运行:

npm run prerender

渲染更多(动态)路线

如配置文件第 41 行所示angular.json,可以列出应用程序的其他已知路由。例如,在我们的例子中,我们可以列出/news/news/1/news/2路由。这将指示构建器也预渲染这些额外的路由。对于惰性加载的模块来说,这一点尤其重要,因为 guess-parser 不容易猜到这些路由。

为了渲染更动态的路由,例如示例应用中的新闻详情页,我们需要更多逻辑。基本上,你需要找到一种方法让预渲染器知道哪些路由需要预渲染。例如,可以定义一个list-routes.js脚本,将所有路由列在一个文本文件中。然后,可以将该文件传递给预渲染脚本,如下所示:

npm run prerender --routesFile routes.txt

下面是一个列出所有必需路由的脚本示例。此文本文件中列出的所有路由在预渲染之前都会添加到配置文件routes数组中已定义的路由中angular.json

// scripts/list-routes.js
const fs = require('fs');
const axios = require('axios');
const endOfLine = require('os').EOL;
const newsDataPath = 'http://localhost:4200/assets/news.json';
const routesFile = './routes.txt';

axios.get(newsDataPath).then(res => {
  const routes = [];
  res.data.forEach(newsitem => {
    routes.push('news/' + newsitem.id);
  });
  fs.writeFileSync(routesFile, routes.join(endOfLine), 'utf8');
}).catch(e => console.log(e));

我们的脚本package.json现在看起来像这样:

// updated package.json
{
  "name": "ng-v9-universal",
  "version": "0.0.0",
  "scripts": {
    "..", "..",
    "list-routes": "node ./scripts/list-routes.js",
    "prerender": "npm run list-routes && ng run ng-v9-universal:prerender --routesFile routes.txt"
  },
  "..": ".."
}

重要提示:运行npm run prerender命令时,请确保应用程序也处于运行状态。静态文件/assets/news.json需要可用,以便应用程序预渲染所有路由!您只需在另一个终端运行 ng serve 即可完成此操作。

结论

我最初是用 Angular v2 和 Universal 来创建这个博客的,在 2016 年的时候,搭建起来并不容易。现在 Universal 和 Angular v9 的结合极大地提升了开发者的体验,现在只需遵循清晰的步骤即可实现。

现在只需一个命令即可测试您的应用程序及其服务器端渲染版本。只需运行npm run dev:ssr即可开始!

预渲染静态路由很容易,除非你使用了延迟加载的路由,否则这些路由很难被猜到guess-parser。你仍然需要一种方法来渲染所有路由。这可以通过将路由列在一个文件中,然后使用选项将其提供给构建器来实现--routesFile。如何获取路由列表由你决定。

进一步阅读

Angular Universal v9:有什么新功能?
Vikram @vikerman:我最近发布的 Angular 团队推文

文章来源:https://dev.to/angular/angular-v9-universal-ssr-and-prerendering-out-of-the-box-33b1
PREV
Automatic Adaptive Images in Angular Applications Introduction Problem to solve Create images of different sizes and formats Picture Element
NEXT
Angular 文件下载进度