Angular13 Angular 部署应用

2024-02-25 开发教程 Angular13 匿名 4

部署

当你准备把 Angular 应用部署到远程服务器上时,有很多可选的部署方式。

最简单的部署选项

在完整部署应用之前,你可以先临时用一种技术来测试流程、构建配置和部署行为。

从磁盘构建和提供服务

在开发过程中,你通常会使用 ​ng serve​ 命令来借助 webpack-dev-server在本地内存中构建、监控和提供服务。但是,当你打算部署它时,就必须使用 ​ng build​ 命令来构建应用并在其它地方部署这些构建成果。

ng build​ 和 ​ng serve​ 在构建项目之前都会清除输出文件夹,但只有 ​ng build​ 命令会把生成的构建成果写入输出文件夹中。

默认情况下,输出目录是 ​dist/project-name/​。要输出到其它文件夹,就要修改 ​angular.json​ 中的 ​outputPath​。

当开发临近收尾时,让本地 Web 服务器使用输出文件夹中的内容提供服务可以让你更好地了解当应用部署到远程服务器时的行为。你需要用两个终端才能体验到实时刷新的特性。

  • 在第一个终端上,在监控(watch)模式下执行 ​ng build​ 命令把该应用编译进 ​dist ​文件夹。
ng build --watch

与 ​ng serve​ 命令一样,当源文件发生变化时,就会重新生成输出文件。

在第二个终端上,安装一个 Web 服务器(比如 lite-server),然后使用输出文件夹中的内容运行它。比如:
lite-server --baseDir="dist/project-name"

每当输出了新文件时,服务器就会自动刷新你的浏览器。

该方法只能用于开发和测试,在部署应用时,它不受支持,也不是安全的方式。

使用 CLI 进行自动部署

Angular CLI 命令 ​ng deploy​(在版本 8.3.0 中引入)执行与你的项目关联的 ​deploy ​CLI 构建器。有许多第三方构建器实现了到不同平台的部署功能。你可以通过运行 ​ng add [package name]​ 把它们中的任何一个添加到项目中。

添加具有部署功能的程序包时,它将为所选项目自动更新自动更新工作区配置(​angular.json​ 文件)中的 ​deploy ​部分。然后,你就可以使用 ​ng deploy​ 命令来部署该项目了。

比如,以下命令将项目自动部署到 Firebase。

ng add @angular/fire
ng deploy

该命令是交互式的。在这种情况下,你必须拥有或创建 Firebase 帐户,并使用该帐户进行身份验证。该命令提示你选择要部署的 Firebase 项目。

该命令会构建你的应用,并将生产环境的资产文件上传到 Firebase。

在下表中,你可以找到实现了到不同平台部署功能的软件包列表。每个软件包的 ​deploy ​命令可能需要不同的命令行选项。你可以通过以下与包名称相关的链接来阅读更多内容:

部署到

Firebase 托管

@angular/fire

Azure

@azure/ng-deploy

Vercel

vercel init angular

Netlify

@netlify-builder/deploy

GitHub pages

angular-cli-ghpages

NPM

ngx-deploy-npm

亚马逊云 S3

@jefiozie/ngx-aws-deploy

如果要部署到自己管理的服务器上,或者缺少针对你喜欢的云平台的构建器,则可以创建支持你使用 ​ng deploy​ 命令的构建器,或者通读本指南以了解如何手动部署应用程序。

最简化的部署方式

最简化的部署方式就是为开发环境构建,并把其输出复制到 Web 服务器上。

  1. 使用开发环境进行构建
ng build
把输出目录(默认为 ​dist/​)下的每个文件都复制到到服务器上的某个目录下。 配置服务器,让缺失的文件都重定向到 ​index.html​ 上。

这是对应用进行生产环境部署的最简方式。

部署到 GitHub Pages

要将 Angular 应用程序部署到 GitHub Pages,请遵循以下步骤:

  1. 为你的项目创建一个 GitHub Pages 仓库
  2. 通过添加指定你在上一步中创建的 GitHub 存储库的远端地址,来在本地项目中配置 ​git​。创建存储库时,GitHub 已提供了这些命令,以便你可以在命令提示符下复制和粘贴它们。尽管 GitHub 会为你填上某些特定于项目的设置,但这些命令应该类似于以下形式:
git remote add origin https://github.com/your-username/your-project-name.git
git branch -M main
git push -u origin main

当你从 GitHub 粘贴这些命令时,它们会自动运行。

创建并签出一个名为 ​gh-pages​ 的 ​git ​分支。
git checkout -b gh-pages
借助 Angular CLI 命令 ​ng build​和以下选项,使用 Github 项目名称构建应用。这里的 ​your_project_name ​是你在步骤 1 中为 GitHub 存储库提供的项目的名称。

确保在项目名称的两边都包含有斜杠,如 ​/your_project_name/ ​的斜杠。

ng build --output-path docs --base-href /your_project_name/
当构建完成时,把 ​docs/index.html​ 复制为 ​docs/404.html​。 提交你的更改,并推送。 在 GitHub 项目页面上,转到 Settings 并向下滚动到 GitHub Pages 部分,以配置要从 docs 文件夹发布的站点。 单击保存。 单击 GitHub Pages 区顶部的 “GitHub Pages” 链接,以查看已部署的应用程序。链接的格式为 ​https://<user_name>.github.io/<project_name>​。

参阅 angular-cli-ghpages,这个包用到了全部这些特性,还提供了一些额外功能。

服务端配置

这一节涵盖了你可能对服务器或准备部署到服务器的文件要做的那些修改。

带路由的应用必须以 index.html 作为后备页面

Angular 应用很适合用简单的静态 HTML 服务器提供服务。 你不需要服务端引擎来动态合成应用页面,因为 Angular 会在客户端完成这件事。

如果该应用使用 Angular 路由器,你就必须配置服务器,让它对不存在的文件返回应用的宿主页(index.html)。

带路由的应用应该支持“深链接”。 所谓深链接就是指一个 URL,它用于指定到应用内某个组件的路径。 比如,​http://www.mysite.com/heroes/42​ 就是一个到英雄详情页面的深链接,用于显示 ​id: 42​ 的英雄。

当用户从运行中的客户端应用导航到这个 URL 时,这没问题。 Angular 路由器会拦截这个 URL,并且把它路由到正确的页面。

但是,当从邮件中点击链接或在浏览器地址栏中输入它或仅仅在英雄详情页刷新下浏览器时,所有这些操作都是由浏览器本身处理的,在应用的控制范围之外。 浏览器会直接向服务器请求那个 URL,路由器没机会插手。

静态服务器会在收到对 ​http://www.mysite.com/​ 的请求时返回 ​index.html​,但是会拒绝对 ​http://www.mysite.com/heroes/42​ 的请求, 并返回一个 ​404 - Not Found​ 错误,除非,它被配置成了返回 ​index.html​。

后备页面配置范例

没有一种配置可以适用于所有服务器。 后面这些部分会描述对常见服务器的配置方式。 这个列表虽然不够详尽,但可以为你提供一个良好的起点。

服务器

详细信息

Apache

向 ​.htaccess​ 文件添加重写规则ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess):

RewriteEngine On
  # If an existing asset or directory is requested go to it as it is
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
  RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
  RewriteRule ^ - [L]
  # If the requested resource doesn't exist, use index.html
  RewriteRule ^ /index.html

Nginx

使用 ​try_files​,如前端控制器模式 Web 应用程序中所述,修改为提供 ​index.html​ :

try_files $uri $uri/ /index.html;

Ruby

使用 ( sinatra ) 和配置服务器 ​server.rb​ 的基本 Ruby 文件创建一个 Ruby 服务器:

require 'sinatra'
# Folder structure
# .
# -- server.rb
# -- public
#    |-- project-name
#        |-- index.html
get '/' do
  folderDir = settings.public_folder + '/project-name' # ng build output folder
  send_file File.join(folderDir, 'index.html')
end

IIS

向 ​web.config​ 添加重写规则,类似于此处显示的规则:

<system.webServer>
  <rewrite>
    <rules>
      <rule name="Angular Routes" stopProcessing="true">
        <match url=".*" />
        <conditions logicalGrouping="MatchAll">
          <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
        </conditions>
        <action type="Rewrite" url="/index.html" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

GitHub 页面

你不能直接配置 GitHub Pages 服务器,但可以添加 404 页面。将 ​index.html​ 复制到 ​404.html​ 中。它仍将作为 404 响应提供,但浏览器将处理该页面并正确加载应用程序。从 main 上的

docs

提供服务创建一个

.nojekyll

文件也是一个好主意

Firebase 托管

添加重写规则

"rewrites": [ {
  "source": "**",
  "destination": "/index.html"
} ]

为 JavaScript 资产配置正确的 MIME 类型

你的所有应用程序 JavaScript 文件都必须由服务器提供出来,并将 Content-Type 标头设置为 ​text/javascript​ 或其他与 JavaScript 兼容的 MIME-type

默认情况下,大多数服务器和托管服务已经这样做了。

如果服务器为 JavaScript 文件配置了错误的 MIME 类型,将导致应用程序无法启动并出现以下错误:

Failed to load module script: The server responded with a non-JavaScript MIME type of "text/plain". Strict MIME type checking is enforced for module scripts per HTML spec.

如果是这种情况,你将需要检查你的服务器配置并将其重新配置为使用 ​Content-Type: text/javascript​ 来提供 ​.js​ 文件。

请求来自另一个服务器的服务(CORS)

Angular 开发者在向与该应用的宿主服务器不同域的服务器发起请求时,可能会遇到一种 跨域资源共享(CORS)错误。 浏览器会阻止该请求,除非得到那台服务器的明确许可。

客户端应用对这种错误无能为力。 服务器必须配置成可以接受来自该应用的请求。 要了解如何对特定的服务器开启 CORS,参阅enable-cors.org

为生产环境优化

production ​配置项指定如下优化特性。

特性

详细信息

预先 (AOT) 编译

预编译 Angular 的组件模板。

生产模式

部署到启用了生产模式的生产环境。

打包

把你的多个应用于库文件拼接到少量包(bundle)中。

缩小

删除多余的空格、注释和可选令牌。

丑化

重写代码,使用简短的、不容易理解的变量名和函数名。

死代码消除

删除未引用过的模块和很多未用到的代码。

启用生产模式

除了构建期优化之外,Angular 还支持运行期生产模式。Angular 应用默认运行在开发模式下,你可以在浏览器的控制台中看到如下信息:

Angular is running in development mode.
Call `enableProdMode()` to enable production mode.

生产模式通过禁用仅供开发用的安全检查和调试工具(比如,expression-changed-after-checked 检测)来提高应用程序性能。使用生产配置构建应用程序时会自动启用 Angular 的运行时生产模式。

惰性加载

通过只加载应用启动时绝对必须的那些模块,你可以极大缩短应用启动的时间。

可以配置 Angular 的路由器,来推迟所有其它模块(及其相关代码)的加载时机,方法有一直等到应用启动完毕,或者当用到时才按需惰性加载。

不要急性(EAGERLY)导入来自惰性加载模块中的任何东西
如果要惰性加载某个模块,就要小心别在应用启动时要急性加载的模块(比如根模块 ​AppModule​)中导入它。 如果那么做,该模块就会立刻加载起来。
配置打包方式时必须考虑惰性加载。 因为默认情况下惰性加载的模块没有在 JavaScript 中导入过,因此打包器默认会排除它们。 打包器不认识路由器配置,也就不能为惰性加载的模块创建独立的包。 你必须手动创建这些包。
CLI 会运行 Angular Ahead-of-Time Webpack 插件,它会自动识别出惰性加载的 ​NgModules​,并为它们创建独立的包。

测量性能

如果你对哪些东西拖慢了应用有更加清晰、精确的了解,就可以更好地决定优化什么以及如何优化。 慢的原因可能和你所想的不一样。 你可能花费了大量的时间和金钱来优化一些实际上无关紧要的东西,甚至可能让应用变得更慢。 你应该测量应用在运行环境中的实际行为,这才是最重要的。

Chrome DevTools 的网络和性能页是你开始学习如何测量性能的好地方。

WebPageTest工具是另一个不错的选择,它还能帮你验证这次部署是否成功。

检查发布包

source-map-explorer 工具可以帮你在生产环境构建之后探查 JavaScript 包。

安装 ​source-map-explorer​ :

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

为生产环境构建应用,包括源码映射表(source map)

ng build --source-map

在 ​dist/​ 目录下列出生成的包。

ls dist/project-name/*.js

运行浏览器来生成其中一个包的图形化表示。 下面的例子展示了 ​main​ 包的图表。

node_modules/.bin/source-map-explorer dist/project-name/main*

source-map-explorer​ 会分析与包一起生成的 source map,并画出所有依赖的地图,精确展示哪些类包含在哪个包中。

下面是范例应用 ​cli-quickstart​ 中 ​main ​包的输出。

base 标签

HTML 的 <base href="..."/> 标签指定了用于解析静态文件(如图片、脚本和样式表)相对地址的基地址。 比如,对于 ​<base href="/my/app/">​,浏览器就会把 ​some/place/foo.jpg​ 这样的 URL 解析成到 ​my/app/some/place/foo.jpg​ 的请求。 在导航期间,Angular 路由器使用 base href 作为到组件模板文件和模块文件的基地址。

在开发期间,你通常会在存有 ​index.html​ 的目录下启动开发服务器。 那就是根目录,你要在 ​index.html​ 的顶部附近添加 ​<base href="/">​,因为 ​/​ 就是该应用的根路径。

但是在共享或生产服务器上,你可能会在子目录下启动服务器。 比如,当前应用的加载地址可能类似于 ​http://www.mysite.com/my/app​,这里的子目录就是 ​my/app/​。所以你就要往服务端版本的 ​index.html​ 中添加 ​<base href="/my/app/">​。

这里如果不配置 ​base ​标签,应用就会失败,并在浏览器的控制台中为缺失的文件显示一个 ​404 - Not Found​ 错误。看看它试图从哪里去查找那些文件,并据此调整 base 标签。

部署 url(deploy-url)

一个命令行选项,用于指定在编译时解析图片、脚本和样式表等资产(assets)的相对 URL 的基础路径。比如:​ng build --deploy-url /my/assets​。

deploy url​ 和 ​base href​ 这两个定义的作用有所重叠。

  • 两者都可用于初始脚本、样式表、惰性脚本和 css 资源。

但是,定义 ​base href​ 有一些独有的作用。

  • 定义 ​base href​ 可用于定位相对路径模板 (HTML) 资产和针对相对路径的 fetch/XMLHttpRequests。

base href​ 也可用于定义 Angular 路由器的默认基础 URL。需要进行更复杂设置的用户可能需要在应用程序中手动配置 ​APP_BASE_HREF ​令牌。(比如,应用程序路由基地址是 ​/​,但各种资产、脚本等都在 ​/assets/​ 下)。

与可以只在一个地方定义的 ​base href​ 不同,​deploy url​ 需要在构建时硬编码到应用程序中。这意味着指定 ​deploy url​ 会降低构建速度,但这是使用在整个应用程序中嵌入自己的选项的代价。这也是为什么说 ​base href​ 通常是更好的选择。