Angular 17 來了,性能大幅提升!
11 月 8 日,Angular 17 正式發布,該版本帶來了很多重要更新,包括:
- 引入了可延遲的視圖,將性能和開發者體驗提升到新的高度。
- 內置控制流循環使運行速度在公共基準測試中提高了高達90%。
- 混合渲染和客戶端渲染的構建速度分別提高了87%和67%。
- 全新的外觀體現了 Angular 未來的功能。
- 全新的互動學習之旅,帶來更好的用戶體驗。
面向未來的品牌形象
經過過去幾個版本的快速發展,Angular 已經迎來了全新的面貌。憑借基于信號的反應性、水化、獨立組件、指令組合等創新功能,它已經得到了數百萬開發人員的實戰檢驗和廣泛喜愛。
盡管Angular發展迅速,但其品牌形象一直未能跟上——自AngularJS早期以來幾乎保持不變。今天,這個備受矚目的框架煥然一新,以反映其前瞻性的開發者體驗和卓越性能,進一步引領 Web 開發的新潮流。
Angular 全新的 Logo 如下:
面向未來的文檔
除了新品牌,Angular 團隊還為 Angular 官方文檔開發了一個全新的主頁:angular.dev。針對新的文檔網站,Angular 團隊設計了一個全新的結構、提供了全新的指南、改進了內容質量,并構建了一個互動學習平臺,以便讓開發者在瀏覽器中按照自己的進度學習 Angular 和 Angular CLI。
新的交互式學習體驗由 WebContainers 提供支持,可以在任何現代 Web 瀏覽器中使用 Angular CLI 的強大功能!
今天,正式推出 angular.dev 的 Beta 預覽版,并計劃在 v18 版本中將其設為 Angular 的默認官方網站。
下面來看看 Angular 17 中新增的功能。
內置控制流
為了提升開發者的體驗,Angular 17 引入了新的塊模板語法,它通過簡單且聲明式的 API 提供了強大的功能。在幕后,Angular 編譯器將此語法轉化為高效的 JavaScript 指令,從而實現了控制流、延遲加載等更多操作。
為了解決開發人員在使用 *ngIf, *ngSwitch, 和 *ngFor 時的困擾,v17 中采用了新的塊語法以優化內置控制流。在經過用戶研究和收集社區與合作伙伴的反饋后,決定為 Angular 創建一個內置的控制流,致力于提高開發體驗!
內置控制流可以:
- 更符合人體工程學的語法,讓代碼更加直觀,減少文檔查找的需求。
- 通過更優化的類型檢查,提供更好的類型安全性。
- 該功能主要在構建時起作用,最大限度地減少了運行時占用空間,從而有可能將包大小減少30kb,同時提高 Core Web Vital 得分。
- 無需額外導入,該功能自動適用于模板。
條件語句
先來使用*ngIf來實現條件語句。
<div *ngIf="loggedIn; else anonymousUser">
用戶已登錄
</div>
<ng-template #anonymousUser>
用戶未登錄
</ng-template>
使用內置 if 語句,此條件將如下所示:
@if (loggedIn) {
用戶已登錄
} @else {
用戶未登錄
}
與傳統的 *ngIf 相比,內置 if 語句的 @else 子句提供了更加簡潔的條件判斷。此外,當前的控制流使得 @else if 的實現變得輕而易舉,這在傳統的 *ngIf 中是不可能的。
在*ngSwitch中,改進的人體工程學表現得更為明顯:
<div [ngSwitch]="accessLevel">
<admin-dashboard *ngSwitchCase="admin"/>
<moderator-dashboard *ngSwitchCase="moderator"/>
<user-dashboard *ngSwitchDefault/>
</div>
通過內置控制流,它變成了:
@switch (accessLevel) {
@case ('admin') { <admin-dashboard/> }
@case ('moderator') { <moderator-dashboard/> }
@default { <user-dashboard/> }
}
新的控制流可以在 @switch 中的各個分支中實現更好的類型縮小,這在 *ngSwitch 中是不可能的。
內置for循環
新版本還引入了內置的 for 循環,它極大地改善了開發者體驗,并將 Angular 的渲染速度提升到了全新的高度!
其基本語法是:
@for (user of users; track user.id) {
{{ user.name }}
} @empty {
用戶列表為空
}
我們經常遇到由于 *ngFor 中缺少 trackBy 函數而導致的性能問題。@for 的不同之處在于,為了確??焖俚谋容^性能,track 是必需的。此外,由于它只是一個表達式而不是組件類中的方法,因此使用起來更加簡單。內置的 @for 循環還提供了一個快捷方式,可以輕松遍歷零個項目的集合,這是通過可選的 @empty 塊實現的。
@for 語句使用了新的 diff 算法,與 *ngFor 相比具有更優化的實現,這使得社區框架基準測試的運行時間提高了 90%!
內置控制流的設計目標之一是實現完全自動化的遷移。要在現有項目中嘗試它,可以使用以下命令遷移:
ng generate @angular/core:control-flow
可延遲的視圖
利用新開發的塊語法,創建了一個強大而高效的新機制,可以讓應用運行得更快。可延遲的視圖通過前所未有的便捷性,實現了聲明性且強大的延遲加載,從而將性能和開發者體驗提升到了新的高度。
假設有一個博客頁面,希望實現用戶評論列表的延遲加載。當前需要使用 ViewContainerRef,同時還要處理各種復雜性,如清理、錯誤管理、占位符顯示等。處理這些邊角情況可能會涉及一些復雜的代碼,給測試和調試帶來困難。
新的可延遲視圖只需一行聲明性代碼就可以延遲加載注釋列表及其所有傳遞依賴項:
@defer {
<comment-list />
}
這一切都是通過編譯時的轉換實現的:Angular 找到了 @defer 塊內使用的組件、指令和管道,將所有復雜性抽象化,生成動態導入,并管理加載和狀態切換過程。
使用IntersectionObserver API來實現視口進入時的延遲加載組件涉及復雜的邏輯。然而,Angular 簡化了這個過程,只需添加一個可延遲的視圖觸發器即可!
@defer (on viewport) {
<comment-list />
} @placeholder {
<img src="comments-placeholder.png">
}
在上面的示例中,Angular 首先渲染占位符塊的內容。當它在視口中可見時, 組件就會開始加載。加載完成后,Angular 會刪除占位符并渲染組件。
還有用于加載和錯誤狀態的塊:
@defer (on viewport) {
<comment-list/>
} @loading {
Loading…
} @error {
Loading failed :(
} @placeholder {
<img src="comments-placeholder.png">
}
Angular 為開發者管理了大量的復雜性。
可延遲視圖提供了更多觸發器:
- on idle — 在瀏覽器閑置時延遲加載塊。
- on immediate — 自動開始延遲加載,不會阻塞瀏覽器。
- on timer(time) — 使用計時器延遲加載,時間可自定義。
- on viewport和on viewport(ref) — viewport 還允許為錨元素指定一個引用。當錨元素可見時,Angular 會延遲加載組件并渲染它。
- on interaction 和 on interaction(ref) — 允許在用戶與特定元素交互時啟動延遲加載。
- on hover 和 on hover(ref) — 當用戶懸停元素時觸發延遲加載。
- when expr — 允許通過返回一個 promise 的表達式來指定自定義條件。
可延遲視圖還提供了在渲染依賴項之前預取依賴項的能力。添加預取就像向 defer 塊添加預取語句一樣簡單,并且支持所有相同的觸發器。
@defer (on viewport; prefetch on idle) {
<comment-list />
}
改進的混合渲染體驗
該版本在ng new中加入了提示,使服務端渲染(SSR)和靜態站點生成(SSG或預渲染)更易于使用。
或者,可以通過以下方式在新項目中啟用 SSR:
ng new my-app --ssr
新的 @angular/ssr 包
已經將 Angular 通用存儲庫移至 Angular CLI 存儲庫,使服務端渲染成為 Angular 工具產品中不可或缺的一部分!
從今天開始,要向現有應用添加混合渲染支持,可以運行以下命令:
ng add @angular/ssr
此命令將生成服務器入口點,并自動添加 SSR 和 SSG 構建功能,同時默認啟用 hydration。@angular/ssr 提供了與當前處于維護模式的 @nguniversal/express-engine 相同的功能。如果你的項目正在使用 express-engine,Angular CLI 將自動將代碼更新為 @angular/ssr。
通過將 NgOptimizedImage 與帶有 DOM Hydration 的 Angular SSR 結合使用,累積布局偏移平均減少了 99.4%。
使用 SSR 部署應用
為了進一步增強開發人員體驗,Angular 團隊與云提供商密切合作,以實現順利部署到他們的平臺。
Firebase 現在將通過其新的框架感知CLI的早期預覽,以近乎零配置自動識別和部署 Angular 應用。
firebase experiments:enable webframeworks
firebase init hosting
firebase deploy
框架感知的 CLI 可識別 SSR、i18n、圖像優化等的使用,使開發者能夠在經濟高效的 serverless 基礎設施上提供高性能的 Web 應用。
對于那些擁有復雜 Angular monorepos 或只是喜歡原生工具的人,AngularFire 允許使用 ng deploy
部署到 Firebase:
ng add @angular/fire
ng deploy
為了實現在邊緣工作站上的部署,啟用了 Angular 服端渲染的ECMAScript模塊支持,引入了一個用于HttpClient
的fetch后端,并與 CloudFlare 合作簡化了這一過程。
新的生命周期 Hooks
為了提高 Angular 的 SSR 和 SSG 的性能,從長遠來看,Angular 團隊希望擺脫 DOM 模擬和直接 DOM 操作。同時,在大多數應用的生命周期中,它們需要與元素交互以實例化第三方庫、測量元素大小等。
為了實現這一點,Angular 團隊開發了一組新的生命周期掛鉤:
- afterRender — 注冊一個回調,每次應用程序完成渲染時調用。
- afterNextRender — 注冊一個回調,以便在應用程序下次完成渲染時調用。
只有瀏覽器會調用這些 Hooks,這樣就能夠將自定義 DOM 邏輯安全地直接插入到組件中。例如,如果想實例化一個圖表庫,可以使用 afterNextRender:
@Component({
selector: 'my-chart-cmp',
template: `<div #chart>{{ ... }}</div>`,
})
export class MyChartCmp {
@ViewChild('chart') chartRef: ElementRef;
chart: MyChart|null;
constructor() {
afterNextRender(() => {
this.chart = new MyChart(this.chartRef.nativeElement);
}, {phase: AfterRenderPhase.Write});
}
}
每個鉤子都支持一個“相位值”(例如讀取、寫入),Angular 使用這個相位值來合理安排回調的執行時間,從而減少頁面布局的頻繁變化,提高整體性能。
新項目默認使用 Vite 和 esbuild
在v16版本中,首次引入了 esbuild 和 Vite 驅動的構建體驗作為開發預覽。自此,許多開發人員進行了嘗試,一些企業合作伙伴反饋稱他們的一些應用的構建時間縮短了67%!在 v17 中,新應用的構建器已經從開發預覽階段正式推出,并默認應用于所有新應用!
此外,在使用混合渲染時,更新了構建管道。通過使用SSR和SSG,ng build的構建速度提高了87%,ng serve的編輯刷新循環速度加快了80%。
在未來的次要版本中,將提供原理圖,以使用混合渲染(使用 SSG 或 SSR 進行客戶端渲染)自動遷移現有項目。
DevTools 中的依賴注入調試
去年,Angular 團隊展示了 Angular DevTools 中依賴注入調試功能的預覽。在過去的幾個月里,實現了全新的調試 API,能夠插入框架的運行時并檢查注入器樹。
基于這些 API,構建了一個檢查用戶界面,可以預覽:
- 組件檢查器中組件的依賴關系。
- 注入器樹和依賴關系解析路徑。
- 單個注入器內標明的供應商。