使用 Angular 構(gòu)建跨平臺應用

教程取自于Google官方課程之Cross Platform apps with Angular

了解 Angular 為了幫助開發(fā)者快速設置可維護且可擴縮的應用而提供的各種開發(fā)者工具,包括新工具和現(xiàn)有的工具。

Angular

什么是 Angular?

Angular 是一個基于 TypeScript 構(gòu)建的開發(fā)平臺。它包括:

  • 一個基于組件的框架,用于構(gòu)建可伸縮的 Web 應用
  • 一組完美集成的庫,涵蓋各種功能,包括路由、表單管理、客戶端-服務器通信等
  • 一套開發(fā)工具,可幫助你開發(fā)、構(gòu)建、測試和更新代碼

借助 Angular,無論單人項目還是企業(yè)級應用,你都能獲得平臺帶來的優(yōu)勢。 Angular 的設計目標之一就是讓更新更容易,因此你可以用最小的成本升級到最新的 Angular 版本。

1 Angular 命令行界面 (CLI) 入門

CLI 概覽與命令參考手冊

Angular CLI 是一個命令行界面工具,可用于初始化、開發(fā)、構(gòu)建和維護 Angular 應用。 你可以在命令行窗口中直接使用此工具,也可以通過 Angular Console 這樣的交互式界面來間接使用。

安裝 Angular CLI

Angular CLI 的主版本會跟隨它所支持的 Angular 主版本,不過其小版本可能會獨立發(fā)布。

使用 npm 包管理器來安裝 CLI:

npm install -g @angular/cli

關于版本變更的詳情,以及如何從以前版本升級的信息,參閱 GitHub 上的 Releases 頁:https://github.com/angular/angular-cli/releases

基本工作流

通過 ng 可執(zhí)行文件可以在命令行上調(diào)用此工具。 命令行中還提供了聯(lián)機幫助。 輸入下列命令列出命令或指定命令(如 generate)選項的簡短說明。

ng help
ng generate --help

要想創(chuàng)建、構(gòu)建或在開發(fā)服務器上運行一個新的、基本的 Angular 項目,請到這個新工作區(qū)的上級目錄中運行下列命令:

ng new my-first-project
cd my-first-project
ng serve

在瀏覽器中,打開 http://localhost:4200/ 查看運行效果。 當你使用 ng serve 命令來構(gòu)建應用并在本地啟動開發(fā)服務器時,服務器會自動重新構(gòu)建此應用,并在修改源碼時重新加載此頁面。

當你運行 ng new my-first-project 時,將在當前工作目錄中創(chuàng)建一個名為 my-first-project 的新文件夾。由于你希望在該文件夾中創(chuàng)建文件,因此在運行命令之前,請確保你在當前工作目錄中具有足夠的權(quán)限。
如果當前工作目錄不適合放你的項目,可以先運行 cd <path-to-other-directory> 來切換到更合適的目錄。

工作區(qū)與項目文件

ng new 命令會創(chuàng)建一個 Angular 工作區(qū)目錄,并生成一個新的應用骨架。 每個工作區(qū)中可以包含多個應用和庫。 由 ng new 命令創(chuàng)建的初始應用位于工作區(qū)的頂層。 你在工作區(qū)中生成的其它應用或庫,會放在 projects/ 子目錄下。

新生成的應用中包含根模塊的源碼,還有根組件和模板。 每個應用都有一個 src 目錄,其中包含邏輯、數(shù)據(jù)和靜態(tài)文件。

你可以直接編輯這些生成的文件,也可以使用 CLI 命令來添加或修改它們。 使用 ng generate 命令也可以添加其它組件和服務,以及管道、指令的源碼等。 必須在工作區(qū)或項目目錄下才能執(zhí)行 addgenerate 之類的命令,因為這些命令需要在應用或庫上進行創(chuàng)建或其它操作。

工作區(qū)與項目的配置

工作區(qū)的配置文件 angular.json 位于此工作區(qū)的頂層。 在這里,你可以設置全工作區(qū)范圍的默認值,并指定當 CLI 為不同目標構(gòu)建項目時要用到的配置。

ng config 讓你可以從命令行中設置和獲取配置項的值。你也可以直接編輯 angular.json 文件。 注意,此配置文件中的選項名稱必須使用小駝峰(camelCase)形式,不過當在命令行中提供它是可以使用小駝峰和中線分隔(dash-case)兩種形式。


CLI 命令語法

命令語法如下:

ng commandNameOrAlias requiredArg [optionalArg] [options]

  • 大多數(shù)命令以及少量選項,會有別名。別名會顯示在每個命令的語法描述中。

  • 選項名帶有雙中線前綴(--)。 選項別名帶有單中線前綴(-)。 參數(shù)沒有前綴。 比如:

ng build my-app -c production
  • 通常,生成的工件(artifact)名稱可以作為命令的參數(shù)進行指定,也可以使用 --name 選項。

  • 參數(shù)和選項的名稱可以用小駝峰或中線分隔的格式給出。 --myOptionName 等價于 --my-option-name

邏輯型選項

邏輯型選項有兩種形式:--this-option 可以把標志設置為 true,而 --no-this-option 可以把它設置為 false。 如果沒有提供選項,該標志就會留在文檔中所列出的默認狀態(tài)。

相對路徑

用來指定文件的選項可以用絕對路徑,也可以用相對于當前目錄的相對路徑,當前目錄通常是工作區(qū)或項目的根目錄。

原理圖(schematics)

ng generateng add 命令會把要生成或要添加到當前項目中的工件或庫作為參數(shù)。 除了通用選項之外,每個工件或庫還可以用原理圖定義自己的選項。 原理圖的選項和內(nèi)置命令的選項使用同樣的格式。

2 使用 Angular 開發(fā)者工具進行調(diào)試

DevTools 概述

Angular DevTools 是一個 Chrome 擴展程序,可為 Angular 應用程序提供調(diào)試和剖析功能。 Angular DevTools 支持 Angular v9 及更高版本,并支持 Ivy。

你可以在 Chrome 網(wǎng)上應用店中找到 Angular DevTools。

安裝 Angular DevTools 后,你可以在 Chrome DevTools 的 Angular 標簽下找到本擴展程序。


Angular DevTools

打開擴展程序時,你還會看到另外兩個選項卡:

  • Components - 使你可以瀏覽應用程序中的組件和指令,并預覽或編輯它們的狀態(tài)。

  • Profiler - 使你可以剖析應用程序并了解變更檢測執(zhí)行期間的性能瓶頸。

    Components and Profiler

在 Angular DevTools 的右上角,你將找到頁面上正在運行哪個版本的 Angular 以及該擴展的最后一次提交的哈希串。


調(diào)試你的應用程序

Components 選項卡使你可以瀏覽應用程序的結(jié)構(gòu)。你可以可視化并檢查組件和指令實例,并預覽或修改它們的狀態(tài)。在接下來的兩節(jié)中,我們將研究如何有效使用此選項卡來調(diào)試應用程序。

瀏覽應用程序的結(jié)構(gòu)
瀏覽應用程序的結(jié)構(gòu)
查看屬性

單擊組件瀏覽器中的各個組件或指令,以選擇它們并預覽其屬性。 Angular DevTools 在組件樹的右側(cè)顯示其屬性和元數(shù)據(jù)。

可以使用鼠標或下列鍵盤快捷鍵在組件樹中導航:

  • 用上下箭頭鍵選擇上一個或下一個節(jié)點。

  • 用左右箭頭鍵折疊或展開一個節(jié)點。

要通過名稱查找組件或指令,請使用組件樹上方的搜索框。要導航至下一個搜索匹配項,請按 Enter。要導航至上一個搜索匹配項,請按 Shift + Enter

查看屬性
導航到宿主節(jié)點

要轉(zhuǎn)到特定組件或指令的宿主元素,請在組件瀏覽器中找到它,然后雙擊它。 Chrome DevTools 將打開 “Elements” 選項卡,然后選擇關聯(lián)的 DOM 節(jié)點。

導航到源碼

對于組件,Angular DevTools 還允許你導航到源碼選項卡中的組件定義。選擇特定組件后,單擊屬性視圖右上角的圖標:

導航到源碼
修改屬性值

與 Chrome DevTools 一樣,屬性視圖可讓你編輯輸入屬性、輸出屬性或其他屬性的值。右鍵單擊屬性值。如果此值類型可使用編輯功能,則將看到一個文本輸入框。鍵入新值,然后按 Enter 鍵。

修改屬性值
在控制臺中訪問選定的組件或指令

作為控制臺中的快捷方式,Angular DevTools 可以讓你訪問最近選擇的組件或指令的實例。鍵入 $ng0 以獲取對當前所選組件或指令的實例的引用,鍵入 $ng1 來獲取前一個選擇的實例。

在控制臺中訪問選定的組件或指令
選擇指令或組件

與 Chrome DevTools 相似,你可以檢查頁面以選擇特定的組件或指令。單擊Devtools 中左上角的 Inspect element(審查元素)圖標,然后將鼠標懸停在頁面上的 DOM 元素上。 Angular DevTools 可以識別關聯(lián)的指令和/或組件,并允許你在組件樹中選擇相應的元素。

選擇指令或組件

剖析你的應用程序

Profiler 選項卡使你可以預覽 Angular 變更檢測的執(zhí)行。

Profiler 選項卡

通過 Profiler,你可以開始進行剖析或?qū)氍F(xiàn)有的剖析記錄文件。要開始對應用程序進行性能剖析,請將鼠標懸停在 Profiler 選項卡內(nèi)左上角的圓圈上,然后點擊 Start recording

在剖析過程中,Angular DevTools 會捕獲執(zhí)行過的事件,例如變更檢測和生命周期掛鉤。要完成錄制,請再次單擊那個圓圈以 Stop recording

你也可以導入現(xiàn)有剖析記錄。在導入記錄部分了解有關此功能的更多信息。

了解應用程序的執(zhí)行過程

在下面的屏幕截圖中,可以在完成錄制后找到 Profiler 的默認視圖。

Profiler 的默認視圖

在此視圖的頂部附近,你可以看到一系列條形圖,每個條形圖表示應用程序中的變更檢測周期。豎線越高,應用程序在此周期中花費的時間越長。選擇條形圖時,DevTools 會渲染一個條形圖,其中包含在此循環(huán)中捕獲的所有組件和指令。

渲染一個條形圖

在變更檢測時間軸前面,你可以發(fā)現(xiàn) Angular 在此周期中花費了多少時間。 Angular DevTools 會試圖估算出掉幀情況,以指示應用程序的執(zhí)行何時可能會影響用戶體驗。

Angular DevTools 還會指出觸發(fā)這次變更檢測的原因(即變更檢測的來源)。

了解組件的執(zhí)行過程

單擊條形圖時,你會發(fā)現(xiàn)有關應用程序在特定指令或組件上花費了多少時間的詳細視圖:

了解組件的執(zhí)行過程

這張圖展示了 NgForOf 指令花費的總時間,以及其中調(diào)用了哪個方法。它還展示了所選指令的父級層次。

分層視圖
分層視圖

你也可以在類似火焰圖的視圖中預覽變更檢測的執(zhí)行情況。該圖形中的每個圖塊代表屏幕上渲染樹中位于特定位置的元素。

例如,如果在組件樹中特定位置的一個變更檢測周期中,我們原本有一個 ComponentA,然后該組件被刪除,而在它的位置上,Angular 再渲染出 ComponentB,這樣你就會在同一圖塊上看到兩個組件。

每個圖塊的顏色取決于 Angular 在這里花費了多少時間。 DevTools 通過相對于我們花費最多時間進行變更檢測的圖塊所花費的時間來確定顏色的深淺。

單擊某個圖塊時,你會在右側(cè)面板中看到關于該圖塊的詳細信息。雙擊圖塊將其放大,以便你可以預覽嵌套的子級圖塊。

調(diào)試 OnPush

要預覽 Angular 進行變更檢測的組件,請選擇火焰圖上方頂部的 Change detection 復選框。

此視圖將把所有在 Angular 中執(zhí)行過變更檢測的圖塊顯示為綠色,其余顯示為灰色:

調(diào)試 OnPush
導入剖析記錄

單擊已記錄的性能剖析會話左上角的 Save Profile 按鈕,以將其導出為 JSON 文件并將其保存到磁盤。然后,你可以通過單擊 Choose file 輸入框來將此文件導入到剖析器的初始視圖中:

導入剖析記錄

3 使用 Angular Universal 進行服務器端渲染

Angular Universal:Angular 統(tǒng)一平臺簡介

本指南講的是Angular Universal(統(tǒng)一平臺),一項在服務端運行 Angular 應用的技術(shù)。

標準的 Angular 應用會運行在瀏覽器中,它會在 DOM 中渲染頁面,以響應用戶的操作。 而Angular Universal 會在服務端運行,生成一些靜態(tài)的應用頁面,稍后再通過客戶端進行啟動。 這意味著該應用的渲染通常會更快,讓用戶可以在應用變得完全可交互之前,先查看應用的布局。

要了解 SSR 的其它技術(shù)和概念的詳細信息,請參閱這篇文章

可以使用 Angular CLI 來輕松為應用做好服務端渲染的準備。CLI 的 @nguniversal/express-engine 模板會執(zhí)行如下必要步驟。

Angular Universal 需要活躍 LTS 或 維護中 LTS版本的 Node.js。 參見 package.json 文件中的 engines 屬性,以了解當前支持的版本。

注意: <live-example downloadonly="" ng-version="13.0.3">下載已完成的范例代碼</live-example>,并將其運行在一個 Node.js? Express 服務器中。

Universal 教程

這次演練的基礎是“英雄之旅”教程。

在這個例子中,Angular CLI 使用 預先(AoT)編譯器編譯并打包了該應用的 Universal 版本。Node.js Express Web 服務器則會根據(jù)客戶端的請求,利用 Universal 編譯 HTML 頁面。

要創(chuàng)建服務端應用模塊 app.server.module.ts,請運行以下 CLI 命令。

ng add @nguniversal/express-engine

該命令會創(chuàng)建如下文件夾結(jié)構(gòu)。

src/
  index.html                 app web page
  main.ts                    bootstrapper for client app
  main.server.ts             * bootstrapper for server app
  style.css                  styles for the app
  app/ ...                   application code
    app.server.module.ts     * server-side application module
server.ts                    * express web server
tsconfig.json                TypeScript base configuration
tsconfig.app.json            TypeScript browser application configuration
tsconfig.server.json         TypeScript server application configuration
tsconfig.spec.json           TypeScript tests configuration

標有 * 的文件都是新增的,不在原始的教程范例中。

Universal 實戰(zhàn)

要使用 Universal 在本地系統(tǒng)中渲染你的應用,請使用如下命令。

npm run dev:ssr

打開瀏覽器,導航到 http://localhost:4200/。你會看到熟悉的“英雄之旅”儀表盤頁面。

通過 routerLinks 導航時能正常工作,因為它們使用的是內(nèi)置的鏈接標簽(<a>)。你可以從儀表盤進入 英雄列表頁面,然后返回。你可以點擊儀表盤頁面上的一個英雄來顯示他的詳情頁面。

如果你限制下網(wǎng)速(稍后會講操作步驟),讓客戶端腳本下載時間變長,你會注意到:

  • 你無法添加或刪除英雄。

  • 儀表盤頁面上的搜索框會被忽略。

  • “詳情”頁面上的后退保存按鈕不起作用。

不支持除了點擊 [routerLink](http://angular.cn/api/router/RouterLink) 以外的任何用戶事件。你必須等待完整的客戶端應用啟動并運行,或者使用 preboot 之類的庫來緩沖這些事件,這樣你就可以在客戶端腳本加載完畢后重放這些事件。

在開發(fā)機器上,從服務端渲染的應用過渡到客戶端應用的過程會很快,但是你還是應該在實際場景中測試一下你的應用。

你可以通過模擬速度較慢的網(wǎng)絡來更清晰地看到這種轉(zhuǎn)換,如下所示:

  1. 打開 Chrome 開發(fā)者工具,進入 Network 標簽頁。

  2. 找一下菜單欄最右側(cè)的 Network Throttling 下拉菜單。

  3. 嘗試一下 “3G” 的速度吧。

服務端渲染的應用仍然可以快速啟動,但完整的客戶端應用可能需要幾秒鐘才能加載完。


為何需要服務端渲染?

有三個主要的理由來為你的應用創(chuàng)建一個 Universal 版本。

  1. 通過搜索引擎優(yōu)化(SEO)來幫助網(wǎng)絡爬蟲。

  2. 提升在手機和低功耗設備上的性能

  3. 迅速顯示出第一個支持首次內(nèi)容繪制(FCP)的頁面

幫助網(wǎng)絡爬蟲(SEO)

Google、Bing、Facebook、Twitter 和其它社交媒體網(wǎng)站都依賴網(wǎng)絡爬蟲去索引你的應用內(nèi)容,并且讓它的內(nèi)容可以通過網(wǎng)絡搜索到。

這些網(wǎng)絡爬蟲可能不會像人類那樣導航到你的具有高度交互性的 Angular 應用,并為其建立索引。

Angular Universal 可以為你生成應用的靜態(tài)版本,它易搜索、可鏈接,瀏覽時也不必借助 JavaScript。 它也讓站點可以被預覽,因為每個 URL 返回的都是一個完全渲染好的頁面。

提升手機和低功耗設備上的性能

有些設備不支持 JavaScript 或 JavaScript 執(zhí)行得很差,導致用戶體驗不可接受。 對于這些情況,你可能會需要該應用的服務端渲染的、無 JavaScript 的版本。 雖然有一些限制,不過這個版本可能是那些完全沒辦法使用該應用的人的唯一選擇。

快速顯示第一頁

快速顯示第一頁對于吸引用戶是至關重要的。 加載速度更快的頁面效果更好,即使其差異只有 100 毫秒也是如此(https://web.dev/shopping-for-speed-on-ebay/)。 你的應用要啟動得更快一點,以便在用戶決定做別的事情之前吸引他們的注意力。

使用 Angular Universal,你可以為應用生成“著陸頁”,它們看起來就和完整的應用一樣。 這些著陸頁是純 HTML,并且即使 JavaScript 被禁用了也能顯示。 這些頁面不會處理瀏覽器事件,不過它們可以[[routerLink](http://angular.cn/api/router/RouterLink)](guide/router-reference#router-link) 在這個網(wǎng)站中導航。

在實踐中,你可能要使用一個著陸頁的靜態(tài)版本來保持用戶的注意力。 同時,你也會在幕后加載完整的 Angular 應用。 用戶會覺得著陸頁幾乎是立即出現(xiàn)的,而當完整的應用加載完之后,又可以獲得完整的交互體驗。


Universal Web 服務器

Universal Web 服務器使用 Universal 模板引擎渲染出的靜態(tài) HTML 來響應對應用頁面的請求。 服務器接收并響應來自客戶端(通常是瀏覽器)的 HTTP 請求,并回復靜態(tài)文件,如腳本、CSS 和圖片。 它可以直接響應數(shù)據(jù)請求,也可以作為獨立數(shù)據(jù)服務器的代理進行響應。

這個例子中的范例 Web 服務器是基于常見的 Express 框架的。

注意: 任何一種 Web 服務器技術(shù)都可以作為 Universal 應用的服務器,只要它能調(diào)用 Universal 的 [renderModule](http://angular.cn/api/platform-server/renderModule)() 函數(shù)。 這里所討論的這些原則和決策點也適用于任何 Web 服務器技術(shù)。

Universal 應用使用 platform-server 包(而不是 platform-browser),它提供了 DOM 的服務端實現(xiàn)、XMLHttpRequest 以及其它不依賴瀏覽器的底層特性。

服務器(這個例子中使用的是 Node.js Express 服務器)會把客戶端對應用頁面的請求傳給 NgUniversal 的 ngExpressEngine。在內(nèi)部實現(xiàn)上,它會調(diào)用 Universal 的 [renderModule](http://angular.cn/api/platform-server/renderModule)() 函數(shù),它還提供了緩存等有用的工具函數(shù)。

[renderModule](http://angular.cn/api/platform-server/renderModule)() 函數(shù)接受一個模板 HTML 頁面(通常是 index.html)、一個包含組件的 Angular 模塊和一個用于決定該顯示哪些組件的路由作為輸入。

該路由從客戶端的請求中傳給服務器。

每次請求都會給出所請求路由的一個適當?shù)囊晥D。

[renderModule](http://angular.cn/api/platform-server/renderModule)() 在模板中的 <app> 標記中渲染出這個視圖,并為客戶端創(chuàng)建一個完成的 HTML 頁面。

最后,服務器就會把渲染好的頁面返回給客戶端。

使用瀏覽器 API

由于 Universal 應用并沒有運行在瀏覽器中,因此該服務器上可能會缺少瀏覽器的某些 API 和其它能力。

比如,服務端應用不能引用瀏覽器獨有的全局對象,比如 window、documentnavigatorlocation

Angular 提供了一些這些對象的可注入的抽象層,比如 LocationDOCUMENT,它可以作為你所調(diào)用的 API 的等效替身。 如果 Angular 沒有提供它,你也可以寫一個自己的抽象層,當在瀏覽器中運行時,就把它委托給瀏覽器 API,當它在服務器中運行時,就提供一個符合要求的代用實現(xiàn)(也叫墊片 - shimming)。

同樣,由于沒有鼠標或鍵盤事件,因此 Universal 應用也不能依賴于用戶點擊某個按鈕來顯示某個組件。 Universal 應用必須僅僅根據(jù)客戶端過來的請求決定要渲染的內(nèi)容。 把該應用做成可路由的,就是一種好方案。

Universal 模板引擎

server.ts 文件中最重要的部分是 ngExpressEngine() 函數(shù):

// Our Universal express-engine (found @ https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
  bootstrap: AppServerModule,
}));

ngExpressEngine() 是對 Universal 的 [renderModule](https://angular.cn/api/platform-server/renderModule)() 函數(shù)的封裝。它會把客戶端請求轉(zhuǎn)換成服務端渲染的 HTML 頁面。 它接受一個具有下列屬性的對象:

  • bootstrap:在服務器上渲染時用于引導應用程序的根 [NgModule](https://angular.cn/api/core/NgModule)[NgModule](https://angular.cn/api/core/NgModule) 工廠。對于這個范例應用,它是 AppServerModule。它是 Universal 服務端渲染器和 Angular 應用之間的橋梁。

  • extraProviders:這是可選的,可以讓你指定僅在服務器渲染應用程序時才適用的依賴提供者。當你的應用需要某些只能由當前運行的服務器實例確定的信息時,可以執(zhí)行此操作。

ngExpressEngine() 函數(shù)返回了一個會解析成渲染好的頁面的承諾(Promise)。 接下來你的引擎要決定拿這個頁面做點什么。 在這個引擎Promise 回調(diào)函數(shù)中,把渲染好的頁面返回給了 Web 服務器,然后服務器通過 HTTP 響應把它轉(zhuǎn)發(fā)給了客戶端。

注意: 這個包裝器幫助隱藏了 [renderModule](https://angular.cn/api/platform-server/renderModule)() 的復雜性。 在 Universal 代碼庫中還有更多針對其它后端技術(shù)的包裝器。

過濾請求的 URL

注意:當使用 NgUniversal Express 原理圖時,將自動處理稍后描述的基本行為。當你要嘗試理解其底層行為或在不使用原理圖的情況下自行實現(xiàn)它時,這一節(jié)會很有用。

Web 服務器必須把對應用頁面的請求和其它類型的請求區(qū)分開。

這可不像攔截對根路徑 / 的請求那么簡單。 瀏覽器可以請求應用中的任何一個路由地址,比如 /dashboard、/heroes/detail:12。 事實上,如果應用會通過服務器渲染,那么應用中點擊的任何一個鏈接都會發(fā)到服務器,就像導航時的地址會發(fā)到路由器一樣。

幸運的是,應用的路由具有一些共同特征:它們的 URL 一般不帶文件擴展名。 (數(shù)據(jù)請求也可能缺少擴展名,但是它們很容易識別出來,因為它們總是以 /api 開頭,所有的靜態(tài)資源的請求都會帶有一個擴展名,比如 main.js/node_modules/zone.js/dist/zone.js)。

由于使用了路由,所以我們可以輕松的識別出這三種類型的請求,并分別處理它們。

  1. 數(shù)據(jù)請求:請求的 URL 用 /api 開頭

  2. 應用導航:請求的 URL 不帶擴展名

  3. 靜態(tài)資源:所有其它請求。

Node.js Express 服務器是一系列中間件構(gòu)成的管道,它會挨個對 URL 請求進行過濾和處理。 你可以調(diào)用 app.get() 來配置 Express 服務器的管道,就像下面這個數(shù)據(jù)請求一樣:

// TODO: implement data requests securely
server.get('/api/**', (req, res) => {
  res.status(404).send('data requests are not yet supported');
});

注意:這個范例服務器不會處理數(shù)據(jù)請求。
本教程的“內(nèi)存 Web API” 模塊(一個演示及開發(fā)工具)攔截了所有 HTTP 調(diào)用,并且模擬了遠端數(shù)據(jù)服務器的行為。 在實踐中,你應該移除這個模塊,并且在服務器上注冊你的 Web API 中間件。

下列代碼會過濾出不帶擴展名的 URL,并把它們當做導航請求進行處理。

// All regular routes use the Universal engine
server.get('*', (req, res) => {
  res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
安全的提供靜態(tài)文件

單獨的 server.use() 會處理所有其它 URL,比如對 JavaScript 、圖片和樣式表等靜態(tài)資源的請求。

要保證客戶端只能下載那些允許他們訪問的文件,你應該把所有面向客戶端的資源文件都放在 /dist 目錄下,并且只允許客戶端請求來自 /dist 目錄下的文件。

下列 Node.js Express 代碼會把剩下的所有請求都路由到 /dist 目錄下,如果文件未找到,就會返回 404 - NOT FOUND。

// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
  maxAge: '1y'
}));
在服務端使用絕對 URL 進行 HTTP(數(shù)據(jù))請求

本教程的 HeroServiceHeroSearchService 都委托 Angular 的 [HttpClient](https://angular.cn/api/common/http/HttpClient) 模塊來獲取應用數(shù)據(jù)。這些服務會向 api/heroes 之類的相對 URL 發(fā)送請求。在服務端渲染的應用中,HTTP URL 必須是絕對的(例如,https://my-server.com/api/heroes )。這意味著當在服務器上運行時,URL 必須以某種方式轉(zhuǎn)換為絕對 URL,而在瀏覽器中運行時,它們是相對 URL。

如果你正在使用 @nguniversal/*-engine 包之一(例如 @nguniversal/express-engine),就會自動為幫你做這件事。你無需再做任何事情來讓相對 URL 能在服務器上運行。

如果出于某種原因,你沒有使用 @nguniversal/*-engine 包,你可能需要親自處理它。

建議的解決方案是將完整的請求 URL 傳給 renderModule()renderModuleFactory()options 參數(shù)(具體取決于你在服務器上渲染 AppServerModule 的目的)。此選項的侵入性最小,因為它不需要對應用進行任何更改。這里的“請求 URL” 是指當應用在服務器上渲染時的地址。例如,如果客戶端請求了 https://my-server.com/dashboard 并且要在服務器上渲染該應用以響應該請求,那么 options.url 應設置為 https://my-server.com/dashboard

現(xiàn)在,作為在服務端渲染應用的一部分,每次發(fā)送 HTTP 請求時,Angular 都可以使用這里提供的 options.url 正確地將請求 URL 解析為絕對 URL。

實用腳本

  • npm run dev:ssr

    此命令類似于 ng serve ,它在開發(fā)期間提供實時重新加載,但使用服務器端渲染。該應用程序以監(jiān)視模式運行并在每次更改后刷新瀏覽器。這個命令要比實際的 ng serve 命令慢。

  • ng build && ng run app-name:server

    此命令會在生產(chǎn)模式下構(gòu)建服務器腳本和應用程序。當你要構(gòu)建用于部署的項目時,請使用此命令。

  • npm run serve:ssr

    此命令啟動服務器腳本,用于通過服務器端渲染在本地為應用程序提供服務。它使用由 ng run build:ssr 創(chuàng)建的構(gòu)建工件,因此請確保你也運行了該命令。

    請注意, serve:ssr 不能用于在生產(chǎn)環(huán)境為你的應用程序提供服務,而僅用于在本地測試服務器端渲染的應用程序。

  • npm run prerender

    此腳本可用于預先渲染應用程序的頁面。在此處閱讀有關預先渲染的更多信息。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 太長不讀版: Spring + Angular 的全棧式開發(fā),生產(chǎn)力高、入門難度低(此處省略一萬字),是 Java...
    ThoughtWorks閱讀 2,169評論 1 28
  • 一、 背景介紹: 兩個概念: 關于Angular版本,Angular官方已經(jīng)統(tǒng)一命名Angular 1.x統(tǒng)稱為A...
    Keriy閱讀 74,308評論 9 33
  • 先決條件 在開始之前,請確保你的開發(fā)環(huán)境已經(jīng)包含了 Node.js? 和 npm 包管理器。 Node.js An...
    天降男神閱讀 544評論 0 0
  • 我們很高興地宣布Angular 5.0.0——五角形甜甜圈發(fā)布啦!這又是一個主版本,包含新功能并修復了很多bug。...
    hulaye閱讀 871評論 0 1
  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 13,913評論 2 59

友情鏈接更多精彩內(nèi)容