Category Archives: Angular

Learning Angular Chapter 14 Bringing Applications to Production

第14章 将应用投入生产

一个网页应用通常应该在网络上运行,任何人都能从任何地方访问。 它需要两个关键要素:一个托管应用的网页服务器和一个用于部署到该服务器的生产构建。 本章将重点介绍配方的第二部分。

简而言之,Web应用的生产版本是应用程序代码的优化版本,体积更小、更快、性能更好。 主要,它是一个将应用程序中所有代码文件,应用优化技术,并将其转换为单捆文件的过程。

在前几章中,介绍了构建Angular应用程序的多个环节。 我们只需要最后一环,把我们的应用连接起来,让任何人都能使用,那就是构建并部署到网络服务器上。

在本章中,将了解以下概念:

  • 构建 Angular 应用
  • 限制应用包大小
  • 优化应用包
  • 部署 Angular 应用

构建 Angular 应用

要构建 Angular 应用程序,使用 Angular CLI 的以下命令:

ng build

构建过程启动了 Angular 编译器,它主要收集我们应用代码的所有 TypeScript 和 HTML 文件,并将其转换为 JavaScript。 CSS 样式表文件如 SCSS 被转换为纯 CSS 文件。 构建过程确保了应用程序在浏览器中的快速和最佳渲染。

Angular 应用程序包含多种运行时通常不使用的 TypeScript 文件,如单元测试或工具辅助工具。 编译器通过读取tsconfig.app.json文件的属性来知道构建过程中需要收集哪些文件 :

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./out-tsc/app",
    "types": []
  },
  "files": [
    "src/main.ts"
  ],
  "include": [
    "src/**/*.d.ts"
  ]
}

src/main.ts文件是应用程序的主要入口,帮助 Angular 处理我们应用所需的所有组件、服务和其他 Angular 工件。

ng build命令的输出 如下:

Initial chunk files   | Names         |  Raw size | Estimated transfer size
main-N4USDVTP.js      | main          | 206.91 kB |                55.87 kB
polyfills-SCHOHYNV.js | polyfills     |  34.52 kB |                11.29 kB
styles-5INURTSO.css   | styles        |   0 bytes |                 0 bytes
                      | Initial total | 241.44 kB |                67.16 kB

该输出显示构建 Angular 应用程序时生成的 JavaScript 和 CSS 文件,具体如下:

  • main :我们实际编写的应用程序代码
  • polyfills :旧浏览器功能多重填充
  • styles : 我们应用程序的全局CSS样式

Angular编译器将前述文件输出到dist\appName\browser文件夹中,其中appName是应用程序名称。 它还包含以下文件:

  • favicon.ico :Angular应用的图标
  • index.html : Angular 应用的主 HTML 文件

Angular CLI 的ng build命令可以在两种模式下运行:开发和生产。 默认情况下,它以生产模式运行。 要在开发模式下运行,我们应执行以下 Angular CLI 命令:

ng build --configuration=development

前一个命令的输出如下:

Initial chunk files | Names         | Raw size
main.js             | main          |  1.25 MB | 
polyfills.js        | polyfills     | 90.23 kB | 
styles.css          | styles        | 95 bytes | 
                    | Initial total |  1.35 MB

在之前的输出中,你可能会注意到Initial chunk files的名称不包含哈希号,就像生产构建的情况一样。 在生产模式下,Angular CLI 对应用代码执行多种优化技术,如图像优化和提前编译( AOT,Ahead of Time ),以确保最终输出适合托管在Web服务器和生产环境中。 添加到每个文件上的哈希码确保浏览器缓存在部署新版本应用时会迅速使它们失效。

当我们在开发模式下运行ng build命令时,我们使用了--configuration选项。 --configuration选项允许我们在不同环境中运行 Angular 应用。 我们将在下一节学习如何定义Angular环境。

针对不同环境的构建

有时可能想为多个需要不同变量的环境构建一个 Angular 应用,比如后端 API 端点和应用本地设置。 一个常见的用例是为部署到生产环境前测试应用的临时环境。

Angular CLI 使我们能够为每个环境定义不同的配置,并用每种配置构建我们的应用。 我们可以在将配置名作为参数传递的同时,使用以下语法执行ng build命令:

ng build --configuration=name

我们也可以在其他 Angular CLI 命令中传递配置,如ng serve和ng test。

我们可以使用以下 Angular CLI 命令开始处理环境:

ng generate environments

该命令将在 Angular 项目中创建src\environments文件夹:

  • environment.ts : 应用程序的默认环境,生产过程中使用的环境
  • environment.development.ts : 开发过程中使用的应用环境

它还会在Angular项目的angular.json配置文件中添加一个fileReplacements部分:

"development": {
  "optimization": false,
  "extractLicenses": false,
  "sourceMap": true,
  "fileReplacements": [
    {
      "replace": "src/environments/environment.ts",
      "with": "src/environments/environment.development.ts"
    }
  ]
}

在前面的代码片段中,fileReplacements属性定义了将要使用的环境文件在开发环境中执行构建命令时替换默认配置。如果我们运行 ng build --configuration=development 命令,Angular CLI 将替换应用程序包中的 environment.ts 文件与 environment.development.ts 文件。

每个环境文件导出一个 对象,我们可以定义额外的应用属性,比如后端 API 的 URL:

export const environment = {
  apiUrl: 'https://my-default-url'
};

导出对象的相同属性必须在所有环境文件中定义。

我们需要导入默认环境,才能访问 Angular 应用中的环境属性。 例如,要在主应用组件中使用apiUrl属性,我们应该做以下操作:

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { environment } from '../environments/environment';
@Component({
  selector: 'app-root',
  imports: [RouterOutlet],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})
export class AppComponent {
  title = 'my-app';
  apiUrl = environment.apiUrl;
}

并非 Angular 应用中的所有库都可以导入为 JavaScript 模块,而大多数 Angular 第一方库则是如此。 在下一节中,我们将学习如何导入需要全局窗口对象的库 。

为窗口对象构建

Angular 应用可以使用必须附加到窗口对象上的 jQuery 库。 其他库,如 Bootstrap ,则包含必须包含在应用包中的字体、图标和 CSS 文件。

在所有这些情况下,我们都需要告知 Angular CLI 它们的存在,以便它能将它们包含在最终的捆绑包中。

angular.json配置文件中包含options对象,我们可以用它来定义此类文件:

"options": {
  "outputPath": "dist/my-app",
  "index": "src/index.html",
  "browser": "src/main.ts",
  "polyfills": [
    "zone.js"
  ],
  "tsConfig": "tsconfig.app.json",
  "assets": [
    {
      "glob": "**/*",
      "input": "public"
    }
  ],
  "styles": [
    "src/styles.css"
  ],
  "scripts": []
}

该options对象包含以下我们可以使用的属性:

  • assets : 包含文件夹中的静态文件 ,如图标、字体和翻译。 public
  • styles :包含外部CSS样式表文件。 应用程序的全局 CSS 样式表文件默认包含。
  • scripts :包含外部JavaScript文件。

随着我们在 Angular 应用中添加越来越多的功能,最终的捆绑包最终会变得更大。 在下一节中,我们将学习如何利用预算来缓解这种影响。

限制应用包大小

作为开发者,我们 总是希望为终端用户打造令人印象深刻、具备酷炫功能的应用。 因此,我们不断为Angular应用添加更多功能——有时根据规范,有时则为用户提供额外价值。 然而,给 Angular 应用添加新功能会导致其体积膨胀,这在某个阶段可能不可接受。 为了解决这个问题,我们可以利用 预算。

预算是我们可以在angular.json配置文件中定义的阈值,我们可以确保我们的应用程序的大小不超过这些阈值。为了制定预算,我们可以在build命令中使用生产配置的budges属性:

"budgets": [
  {
    "type": "initial",
    "maximumWarning": "500kB",
    "maximumError": "1MB"
  },
  {
    "type": "anyComponentStyle",
    "maximumWarning": "4kB",
    "maximumError": "8kB"
  }
]

Angular CLI 在创建新的 Angular CLI 项目时定义了之前的默认预算。

我们可以为不同类型的预算定义,比如整个Angular应用或其部分内容。 预算的阈值可以定义为字节、千字节、兆字节或其百分比。 当大小达到或超过定义阈值时,Angular CLI会显示警告或抛出错误。

为了更好地理解,我们来描述之前的默认例子:

  • 当 Angular 应用程序大小超过 500KB 时会显示警告 ,超过 1MB 时会显示错误 。
  • 当任何组件样式的大小超过4KB时会显示警告 ,超过8时会显示错误。

要查看在 Angular 应用中配置预算时可以定义的所有可用选项,请访问官方文档网站的指南 https://angular.dev/tools/cli/build/#configuring-size-budgets

当我们希望在Angular应用大幅增长时提供警报机制,预算是很好的选择。 不过,它们只是信息和预防措施的一层。 在接下来的部分,我们将学习如何最小化我们的丛大小。

优化应用包

正如我们在 构建Angular应用 部分所学 ,Angular CLI在构建Angular应用时执行优化技术。 应用代码中执行的优化过程包括现代的网页技术和工具,包括以下内容:

  • 压缩 :将多行源文件转换为单行,去除空白和注释。 这是一个让浏览器后续更快解析这些文件的过程。
  • 篡改 :将属性和方法重命名为非人类可读的形式,使其难以理解和用于恶意目的。
  • 捆绑 :将应用的所有源文件串接到一个文件中,称为捆绑包。
  • 树摇动 :移除未使用的文件和Angular伪影,如组件和服务,使捆绑包更小。
  • 字体优化 :在应用主HTML文件中内嵌外部字体文件,不阻挡渲染请求。 目前支持Google Fonts和Adobe字体,下载需联网。
  • 构建缓存 :缓存之前的构建状态,运行同一构建时恢复,减少构建应用的时间。

如果 Angular 应用的最终 套件在所有之前的优化技术后仍然较大,我们可以使用调用的外部工具source-map-explorer来调查原因。 也许我们导入了两次 JavaScript 库,或者包含了一个未使用的文件。 该工具会分析我们的应用包,并以可视化方式展示我们使用的所有 Angular 产物和库。 开始使用它时,请做以下操作:

1 从终端安装source-map-explorer包:

npm install source-map-explorer --save-dev 

2 构建你的Angular应用并启用源映射:

ng build --source-map

3 在package.json文件中添加以下脚本 :

"scripts": {
  "ng": "ng",
  "start": "ng serve",
  "build": "ng build",
  "watch": "ng build --watch --configuration development",
  "test": "ng test",
  "analyze": "source-map-explorer"
}

4 对 main bundle文件执行以下命令:

npm run analyze dist/my-app/browser/main*.js 

它将在浏览器中打开 应用捆绑包的可视化表示:

alt text

图14.1:源地图浏览器输出

然后我们可以与它互动并检查它,以了解为什么我们的束仍然过大。 一些原因可能包括:

  • 一个库会被包含在捆绑包中两次
  • 包含一个无法树摇动但目前未使用的库

构建Angular应用后的 最后一步 是将其部署到Web服务器,正如我们在下一节中将学习的那样。

部署 Angular 应用

如果你 已经有一个需要用于 Angular 应用程序的 Web 服务器,可以将输出文件夹的内容复制到该服务器的路径上。 如果要在除根目录之外的其他文件夹中部署它,可以更改 href 属性 在主HTML文件中以以下方式标记:

  • 通过 --base-href 选项 ng build 命令:

    ng build --base-href=/mypath/
  • 设置 baseHref 房产 build 命令 angular.json 配置文件:

"options": {
  "outputPath": "dist/my-app",
  "index": "src/index.html",
  "browser": "src/main.ts",
  "baseHref": "/mypath/",
  "polyfills": [
    "zone.js"
  ],
  "tsConfig": "tsconfig.app.json",
  "assets": [
    {
      "glob": "**/*",
      "input": "public"
    }
  ],
  "styles": [
    "src/styles.css"
  ],
  "scripts": []
}

如果你不想部署到自定义服务器,可以用 Angular CLI 工具部署到 支持的托管服务提供商中,你可以在 https://angular.dev/tools/cli/deployment#automatic-deployment-with-the-cli 找到。

摘要

启用 Angular 应用程序是最简单且最关键的部分,因为它最终使您的优秀应用程序对最终用户开放。 Web 应用程序旨在在一天结束时向最终用户提供体验。

本章中,我们学会了如何构建一个 Angular 应用程序,并使其具备生产准备。 我们还研究了优化最终捆绑包的不同方法,并学会了如何手动、自动地将 Angular 应用程序部署到自定义服务器中,用于其他托管服务提供商。

在下一章中,也就是本书的最后一章,我们将学习如何提升 Angular 应用程序的性能。