Angular 部署應(yīng)用

2022-07-14 11:01 更新

部署

當(dāng)你準(zhǔn)備把 Angular 應(yīng)用部署到遠(yuǎn)程服務(wù)器上時(shí),有很多可選的部署方式。

最簡(jiǎn)單的部署選項(xiàng)

在完整部署應(yīng)用之前,你可以先臨時(shí)用一種技術(shù)來(lái)測(cè)試流程、構(gòu)建配置和部署行為。

從磁盤構(gòu)建和提供服務(wù)

在開發(fā)過(guò)程中,你通常會(huì)使用 ?ng serve? 命令來(lái)借助 webpack-dev-server 在本地內(nèi)存中構(gòu)建、監(jiān)控和提供服務(wù)。但是,當(dāng)你打算部署它時(shí),就必須使用 ?ng build? 命令來(lái)構(gòu)建應(yīng)用并在其它地方部署這些構(gòu)建成果。

?ng build? 和 ?ng serve? 在構(gòu)建項(xiàng)目之前都會(huì)清除輸出文件夾,但只有 ?ng build? 命令會(huì)把生成的構(gòu)建成果寫入輸出文件夾中。

默認(rèn)情況下,輸出目錄是 ?dist/project-name/?。要輸出到其它文件夾,就要修改 ?angular.json? 中的 ?outputPath?。

當(dāng)開發(fā)臨近收尾時(shí),讓本地 Web 服務(wù)器使用輸出文件夾中的內(nèi)容提供服務(wù)可以讓你更好地了解當(dāng)應(yīng)用部署到遠(yuǎn)程服務(wù)器時(shí)的行為。你需要用兩個(gè)終端才能體驗(yàn)到實(shí)時(shí)刷新的特性。

  • 在第一個(gè)終端上,在監(jiān)控(watch)模式下執(zhí)行 ?ng build? 命令把該應(yīng)用編譯進(jìn) ?dist ?文件夾。
  • ng build --watch

    與 ?ng serve? 命令一樣,當(dāng)源文件發(fā)生變化時(shí),就會(huì)重新生成輸出文件。

  • 在第二個(gè)終端上,安裝一個(gè) Web 服務(wù)器(比如 lite-server),然后使用輸出文件夾中的內(nèi)容運(yùn)行它。比如:
  • lite-server --baseDir="dist/project-name"

    每當(dāng)輸出了新文件時(shí),服務(wù)器就會(huì)自動(dòng)刷新你的瀏覽器。

該方法只能用于開發(fā)和測(cè)試,在部署應(yīng)用時(shí),它不受支持,也不是安全的方式。

使用 CLI 進(jìn)行自動(dòng)部署

Angular CLI 命令 ?ng deploy?(在版本 8.3.0 中引入)執(zhí)行與你的項(xiàng)目關(guān)聯(lián)的 ?deploy ?CLI 構(gòu)建器。有許多第三方構(gòu)建器實(shí)現(xiàn)了到不同平臺(tái)的部署功能。你可以通過(guò)運(yùn)行 ?ng add [package name]? 把它們中的任何一個(gè)添加到項(xiàng)目中。

添加具有部署功能的程序包時(shí),它將為所選項(xiàng)目自動(dòng)更新自動(dòng)更新工作區(qū)配置(?angular.json? 文件)中的 ?deploy ?部分。然后,你就可以使用 ?ng deploy? 命令來(lái)部署該項(xiàng)目了。

比如,以下命令將項(xiàng)目自動(dòng)部署到 Firebase。

ng add @angular/fire
ng deploy

該命令是交互式的。在這種情況下,你必須擁有或創(chuàng)建 Firebase 帳戶,并使用該帳戶進(jìn)行身份驗(yàn)證。該命令提示你選擇要部署的 Firebase 項(xiàng)目。

該命令會(huì)構(gòu)建你的應(yīng)用,并將生產(chǎn)環(huán)境的資產(chǎn)文件上傳到 Firebase。

在下表中,你可以找到實(shí)現(xiàn)了到不同平臺(tái)部署功能的軟件包列表。每個(gè)軟件包的 ?deploy ?命令可能需要不同的命令行選項(xiàng)。你可以通過(guò)以下與包名稱相關(guān)的鏈接來(lái)閱讀更多內(nèi)容:

部署到

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

如果要部署到自己管理的服務(wù)器上,或者缺少針對(duì)你喜歡的云平臺(tái)的構(gòu)建器,則可以創(chuàng)建支持你使用 ?ng deploy? 命令的構(gòu)建器,或者通讀本指南以了解如何手動(dòng)部署應(yīng)用程序。

最簡(jiǎn)化的部署方式

最簡(jiǎn)化的部署方式就是為開發(fā)環(huán)境構(gòu)建,并把其輸出復(fù)制到 Web 服務(wù)器上。

  1. 使用開發(fā)環(huán)境進(jìn)行構(gòu)建
  2. ng build
  3. 把輸出目錄(默認(rèn)為 ?dist/?)下的每個(gè)文件都復(fù)制到到服務(wù)器上的某個(gè)目錄下。
  4. 配置服務(wù)器,讓缺失的文件都重定向到 ?index.html? 上。 

這是對(duì)應(yīng)用進(jìn)行生產(chǎn)環(huán)境部署的最簡(jiǎn)方式。

部署到 GitHub Pages

要將 Angular 應(yīng)用程序部署到 GitHub Pages,請(qǐng)遵循以下步驟:

  1. 為你的項(xiàng)目創(chuàng)建一個(gè) GitHub Pages 倉(cāng)庫(kù)
  2. 通過(guò)添加指定你在上一步中創(chuàng)建的 GitHub 存儲(chǔ)庫(kù)的遠(yuǎn)端地址,來(lái)在本地項(xiàng)目中配置 ?git?。創(chuàng)建存儲(chǔ)庫(kù)時(shí),GitHub 已提供了這些命令,以便你可以在命令提示符下復(fù)制和粘貼它們。盡管 GitHub 會(huì)為你填上某些特定于項(xiàng)目的設(shè)置,但這些命令應(yīng)該類似于以下形式:
  3. git remote add origin https://github.com/your-username/your-project-name.git
    git branch -M main
    git push -u origin main

    當(dāng)你從 GitHub 粘貼這些命令時(shí),它們會(huì)自動(dòng)運(yùn)行。

  4. 創(chuàng)建并簽出一個(gè)名為 ?gh-pages? 的 ?git ?分支。
  5. git checkout -b gh-pages
  6. 借助 Angular CLI 命令 ?ng build?和以下選項(xiàng),使用 Github 項(xiàng)目名稱構(gòu)建應(yīng)用。這里的 ?your_project_name ?是你在步驟 1 中為 GitHub 存儲(chǔ)庫(kù)提供的項(xiàng)目的名稱。
  7. 確保在項(xiàng)目名稱的兩邊都包含有斜杠,如 ?/your_project_name/ ?的斜杠。

    ng build --output-path docs --base-href /your_project_name/
  8. 當(dāng)構(gòu)建完成時(shí),把 ?docs/index.html? 復(fù)制為 ?docs/404.html?。
  9. 提交你的更改,并推送。
  10. 在 GitHub 項(xiàng)目頁(yè)面上,轉(zhuǎn)到 Settings 并向下滾動(dòng)到 GitHub Pages 部分,以配置要從 docs 文件夾發(fā)布的站點(diǎn)。
  11. 單擊保存。
  12. 單擊 GitHub Pages 區(qū)頂部的 “GitHub Pages” 鏈接,以查看已部署的應(yīng)用程序。鏈接的格式為 ?https://<user_name>.github.io/<project_name>?。

參閱 angular-cli-ghpages,這個(gè)包用到了全部這些特性,還提供了一些額外功能。

服務(wù)端配置

這一節(jié)涵蓋了你可能對(duì)服務(wù)器或準(zhǔn)備部署到服務(wù)器的文件要做的那些修改。

帶路由的應(yīng)用必須以 index.html 作為后備頁(yè)面

Angular 應(yīng)用很適合用簡(jiǎn)單的靜態(tài) HTML 服務(wù)器提供服務(wù)。 你不需要服務(wù)端引擎來(lái)動(dòng)態(tài)合成應(yīng)用頁(yè)面,因?yàn)?nbsp;Angular 會(huì)在客戶端完成這件事。

如果該應(yīng)用使用 Angular 路由器,你就必須配置服務(wù)器,讓它對(duì)不存在的文件返回應(yīng)用的宿主頁(yè)(index.html)。

帶路由的應(yīng)用應(yīng)該支持“深鏈接”。 所謂深鏈接就是指一個(gè) URL,它用于指定到應(yīng)用內(nèi)某個(gè)組件的路徑。 比如,?http://www.mysite.com/heroes/42? 就是一個(gè)到英雄詳情頁(yè)面的深鏈接,用于顯示 ?id: 42? 的英雄。

當(dāng)用戶從運(yùn)行中的客戶端應(yīng)用導(dǎo)航到這個(gè) URL 時(shí),這沒(méi)問(wèn)題。 Angular 路由器會(huì)攔截這個(gè) URL,并且把它路由到正確的頁(yè)面。

但是,當(dāng)從郵件中點(diǎn)擊鏈接或在瀏覽器地址欄中輸入它或僅僅在英雄詳情頁(yè)刷新下瀏覽器時(shí),所有這些操作都是由瀏覽器本身處理的,在應(yīng)用的控制范圍之外。 瀏覽器會(huì)直接向服務(wù)器請(qǐng)求那個(gè) URL,路由器沒(méi)機(jī)會(huì)插手。

靜態(tài)服務(wù)器會(huì)在收到對(duì) ?http://www.mysite.com/? 的請(qǐng)求時(shí)返回 ?index.html?,但是會(huì)拒絕對(duì) ?http://www.mysite.com/heroes/42? 的請(qǐng)求, 并返回一個(gè) ?404 - Not Found? 錯(cuò)誤,除非,它被配置成了返回 ?index.html?。

后備頁(yè)面配置范例

沒(méi)有一種配置可以適用于所有服務(wù)器。 后面這些部分會(huì)描述對(duì)常見(jiàn)服務(wù)器的配置方式。 這個(gè)列表雖然不夠詳盡,但可以為你提供一個(gè)良好的起點(diǎn)。

服務(wù)器

詳細(xì)信息

Apache

向 ?.htaccess? 文件添加重寫規(guī)則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 應(yīng)用程序中所述,修改為提供 ?index.html? :

try_files $uri $uri/ /index.html;
Ruby

使用 ( sinatra ) 和配置服務(wù)器 ?server.rb? 的基本 Ruby 文件創(chuàng)建一個(gè) Ruby 服務(wù)器:

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? 添加重寫規(guī)則,類似于此處顯示的規(guī)則:

<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 頁(yè)面

你不能直接配置 GitHub Pages 服務(wù)器,但可以添加 404 頁(yè)面。將 ?index.html? 復(fù)制到 ?404.html? 中。它仍將作為 404 響應(yīng)提供,但瀏覽器將處理該頁(yè)面并正確加載應(yīng)用程序。從 main 上的  docs  提供服務(wù)創(chuàng)建一個(gè)  .nojekyll  文件也是一個(gè)好主意

Firebase 托管

添加重寫規(guī)則。

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

為 JavaScript 資產(chǎn)配置正確的 MIME 類型

你的所有應(yīng)用程序 JavaScript 文件都必須由服務(wù)器提供出來(lái),并將 Content-Type 標(biāo)頭設(shè)置為 ?text/javascript? 或其他與 JavaScript 兼容的 MIME-type。

默認(rèn)情況下,大多數(shù)服務(wù)器和托管服務(wù)已經(jīng)這樣做了。

如果服務(wù)器為 JavaScript 文件配置了錯(cuò)誤的 MIME 類型,將導(dǎo)致應(yīng)用程序無(wú)法啟動(dòng)并出現(xiàn)以下錯(cuò)誤:

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.

如果是這種情況,你將需要檢查你的服務(wù)器配置并將其重新配置為使用 ?Content-Type: text/javascript? 來(lái)提供 ?.js? 文件。

請(qǐng)求來(lái)自另一個(gè)服務(wù)器的服務(wù)(CORS)

Angular 開發(fā)者在向與該應(yīng)用的宿主服務(wù)器不同域的服務(wù)器發(fā)起請(qǐng)求時(shí),可能會(huì)遇到一種 跨域資源共享(CORS)錯(cuò)誤。 瀏覽器會(huì)阻止該請(qǐng)求,除非得到那臺(tái)服務(wù)器的明確許可。

客戶端應(yīng)用對(duì)這種錯(cuò)誤無(wú)能為力。 服務(wù)器必須配置成可以接受來(lái)自該應(yīng)用的請(qǐng)求。 要了解如何對(duì)特定的服務(wù)器開啟 CORS,參閱enable-cors.org。

為生產(chǎn)環(huán)境優(yōu)化

?production ?配置項(xiàng)指定如下優(yōu)化特性。

特性

詳細(xì)信息

預(yù)先 (AOT) 編譯

預(yù)編譯 Angular 的組件模板。

生產(chǎn)模式

部署到啟用了生產(chǎn)模式的生產(chǎn)環(huán)境。

打包

把你的多個(gè)應(yīng)用于庫(kù)文件拼接到少量包(bundle)中。

縮小

刪除多余的空格、注釋和可選令牌。

丑化

重寫代碼,使用簡(jiǎn)短的、不容易理解的變量名和函數(shù)名。

死代碼消除

刪除未引用過(guò)的模塊和很多未用到的代碼。

啟用生產(chǎn)模式

除了構(gòu)建期優(yōu)化之外,Angular 還支持運(yùn)行期生產(chǎn)模式。Angular 應(yīng)用默認(rèn)運(yùn)行在開發(fā)模式下,你可以在瀏覽器的控制臺(tái)中看到如下信息:

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

生產(chǎn)模式通過(guò)禁用僅供開發(fā)用的安全檢查和調(diào)試工具(比如,expression-changed-after-checked 檢測(cè))來(lái)提高應(yīng)用程序性能。使用生產(chǎn)配置構(gòu)建應(yīng)用程序時(shí)會(huì)自動(dòng)啟用 Angular 的運(yùn)行時(shí)生產(chǎn)模式。

惰性加載

通過(guò)只加載應(yīng)用啟動(dòng)時(shí)絕對(duì)必須的那些模塊,你可以極大縮短應(yīng)用啟動(dòng)的時(shí)間。

可以配置 Angular 的路由器,來(lái)推遲所有其它模塊(及其相關(guān)代碼)的加載時(shí)機(jī),方法有一直等到應(yīng)用啟動(dòng)完畢,或者當(dāng)用到時(shí)才按需惰性加載

不要急性(EAGERLY)導(dǎo)入來(lái)自惰性加載模塊中的任何東西
如果要惰性加載某個(gè)模塊,就要小心別在應(yīng)用啟動(dòng)時(shí)要急性加載的模塊(比如根模塊 ?AppModule?)中導(dǎo)入它。 如果那么做,該模塊就會(huì)立刻加載起來(lái)。
配置打包方式時(shí)必須考慮惰性加載。 因?yàn)槟J(rèn)情況下惰性加載的模塊沒(méi)有在 JavaScript 中導(dǎo)入過(guò),因此打包器默認(rèn)會(huì)排除它們。 打包器不認(rèn)識(shí)路由器配置,也就不能為惰性加載的模塊創(chuàng)建獨(dú)立的包。 你必須手動(dòng)創(chuàng)建這些包。
CLI 會(huì)運(yùn)行 Angular Ahead-of-Time Webpack 插件,它會(huì)自動(dòng)識(shí)別出惰性加載的 ?NgModules?,并為它們創(chuàng)建獨(dú)立的包。

測(cè)量性能

如果你對(duì)哪些東西拖慢了應(yīng)用有更加清晰、精確的了解,就可以更好地決定優(yōu)化什么以及如何優(yōu)化。 慢的原因可能和你所想的不一樣。 你可能花費(fèi)了大量的時(shí)間和金錢來(lái)優(yōu)化一些實(shí)際上無(wú)關(guān)緊要的東西,甚至可能讓應(yīng)用變得更慢。 你應(yīng)該測(cè)量應(yīng)用在運(yùn)行環(huán)境中的實(shí)際行為,這才是最重要的。

Chrome DevTools 的網(wǎng)絡(luò)和性能頁(yè)是你開始學(xué)習(xí)如何測(cè)量性能的好地方。

WebPageTest工具是另一個(gè)不錯(cuò)的選擇,它還能幫你驗(yàn)證這次部署是否成功。

檢查發(fā)布包

source-map-explorer 工具可以幫你在生產(chǎn)環(huán)境構(gòu)建之后探查 JavaScript 包。

安裝 ?source-map-explorer? :

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

為生產(chǎn)環(huán)境構(gòu)建應(yīng)用,包括源碼映射表(source map)

ng build --source-map

在 ?dist/? 目錄下列出生成的包。

ls dist/project-name/*.js

運(yùn)行瀏覽器來(lái)生成其中一個(gè)包的圖形化表示。 下面的例子展示了 ?main? 包的圖表。

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

?source-map-explorer? 會(huì)分析與包一起生成的 source map,并畫出所有依賴的地圖,精確展示哪些類包含在哪個(gè)包中。

下面是范例應(yīng)用 ?cli-quickstart? 中 ?main ?包的輸出。


base 標(biāo)簽

HTML 的 <base href="..."/> 標(biāo)簽指定了用于解析靜態(tài)文件(如圖片、腳本和樣式表)相對(duì)地址的基地址。 比如,對(duì)于 ?<base href="/my/app/">?,瀏覽器就會(huì)把 ?some/place/foo.jpg? 這樣的 URL 解析成到 ?my/app/some/place/foo.jpg? 的請(qǐng)求。 在導(dǎo)航期間,Angular 路由器使用 base href 作為到組件模板文件和模塊文件的基地址。

在開發(fā)期間,你通常會(huì)在存有 ?index.html? 的目錄下啟動(dòng)開發(fā)服務(wù)器。 那就是根目錄,你要在 ?index.html? 的頂部附近添加 ?<base href="/">?,因?yàn)?nbsp;?/? 就是該應(yīng)用的根路徑。

但是在共享或生產(chǎn)服務(wù)器上,你可能會(huì)在子目錄下啟動(dòng)服務(wù)器。 比如,當(dāng)前應(yīng)用的加載地址可能類似于 ?http://www.mysite.com/my/app?,這里的子目錄就是 ?my/app/?。所以你就要往服務(wù)端版本的 ?index.html? 中添加 ?<base href="/my/app/">?。

這里如果不配置 ?base ?標(biāo)簽,應(yīng)用就會(huì)失敗,并在瀏覽器的控制臺(tái)中為缺失的文件顯示一個(gè) ?404 - Not Found? 錯(cuò)誤。看看它試圖從哪里去查找那些文件,并據(jù)此調(diào)整 base 標(biāo)簽。

部署 url(deploy-url)

一個(gè)命令行選項(xiàng),用于指定在編譯時(shí)解析圖片、腳本和樣式表等資產(chǎn)(assets)的相對(duì) URL 的基礎(chǔ)路徑。比如:?ng build --deploy-url /my/assets?。

?deploy url? 和 ?base href? 這兩個(gè)定義的作用有所重疊。

  • 兩者都可用于初始腳本、樣式表、惰性腳本和 css 資源。

但是,定義 ?base href? 有一些獨(dú)有的作用。

  • 定義 ?base href? 可用于定位相對(duì)路徑模板 (HTML) 資產(chǎn)和針對(duì)相對(duì)路徑的 fetch/XMLHttpRequests。

?base href? 也可用于定義 Angular 路由器的默認(rèn)基礎(chǔ) URL。需要進(jìn)行更復(fù)雜設(shè)置的用戶可能需要在應(yīng)用程序中手動(dòng)配置 ?APP_BASE_HREF ?令牌。(比如,應(yīng)用程序路由基地址是 ?/?,但各種資產(chǎn)、腳本等都在 ?/assets/? 下)。

與可以只在一個(gè)地方定義的 ?base href? 不同,?deploy url? 需要在構(gòu)建時(shí)硬編碼到應(yīng)用程序中。這意味著指定 ?deploy url? 會(huì)降低構(gòu)建速度,但這是使用在整個(gè)應(yīng)用程序中嵌入自己的選項(xiàng)的代價(jià)。這也是為什么說(shuō) ?base href? 通常是更好的選擇。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)