Angular新版(v14-v19)發生的那些事
羅慧真 Anita Lo
- 恆逸教育訓練中心-資深講師
- 技術分類:程式設計
Angular 是由 Google 開發和維護的前端框架,專為建構 Single Page Application (SPA) 而設計。它以 TypeScript
為主要語言,並提供強大的工具,使開發者能夠打造動態、模組化且高效能的 Web 應用。
截至本文撰寫時,Angular 已發展至 Angular 19。本篇文章將聚焦於 Angular 14 至 Angular 19 期間最亮眼的更新,包括 Standalone API、@控制流 以及
Signal,並與您一同探討這些新特性的優勢與應用。
Standalone API 的起源
Standalone 元件是在Version 14引入功能預覽版,Version 16進一步強化其功能,最終在Version 17已經正式成為專案的預設模式。

NgModule 的缺點
在了解Standalone API 之前讓我們先來談談為何會有此項發展。早先Angular 採用的是 NgModule,它的缺點是:
- 需要額外的樣板代碼
AppModule.ts import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule], bootstrap: [AppComponent] }) export class AppModule {}
每個模組需要使用 @NgModule 宣告模組的細節。像是使用declarations 指定Module 中所屬的Component、Directive...,使用imports 匯入其他模組,使用providers 設定服務提供者的相關資訊,整體而言寫法相對繁瑣。
-
模組宣告限制了靈活的需要
Angular必須強制開發者必須把所有的元件納入模組。在維護上帶來了一些麻煩,因為必須考慮某一些共享元件是不是需要使用export 以供其它的模組可以使用。
- 不利於 Tree Shaking的運作而影響效能
在編譯的時候相關依賴的模組會完全的被載入,即使那個功能並沒有被使用。 這會影響到效能,在Standalone的模式下這一點被完全的改善,Angular可以更細緻地進行Tree Shaking,減少不必要的程式代碼的載入。
Standalone API的優勢
- 省略了 NgModule,直接啟動應用
- 不再需要 NgModule,直接用 bootstrapApplication() 啟動應用
- 更直觀、少寫樣板代碼
- 更適合漸進式增強(Progressive Enhancement)
import { bootstrapApplication } from '@angular/platform-browser'; import { AppComponent } from './app.component'; bootstrapApplication(AppComponent);
-
更靈活的元件開發
- Standalone 組件可以獨立存在,不需要 NgModule。
- 只需在 @Component() 裡使用 standalone: true,即可讓元件直接使用,不需要再手動匯入模組。
import { Component } from '@angular/core'; @Component({ selector: 'app-hello', standalone: true, template: `<h1>Hello Angular</h1>` }) export class HelloComponent {}
這個元件可以直接在應用中使用,無需 NgModule!
-
更靈活的 Lazy Loading
在 NgModule 架構下, Lazy Loading 通常需要 RouterModule 配合 forChild(),但 Standalone API 讓這個過程變得更直覺:
import { Route } from '@angular/router'; import { HomeComponent } from './home.component'; export const routes: Route[] = [ { path: '', component: HomeComponent }, { path: 'about', loadComponent: () => import('./about.component').then(m => m.AboutComponent) } ];
- 更好的 Tree Shaking 和效能
由於 Standalone API 讓元件變得更獨立,Angular 可以更有效地進行 Tree Shaking,只打包真正需要的部分,減少應用程式的大小,提升效能。
下面說明Standalone API的好處以及如何將 ngModule 模式轉換成 Standalone 專案模式
NgModule | Standalone API | |
---|---|---|
樣板代碼 | 需要大量設定 | 省略 NgModule,簡單直觀 |
元件管理 | 需要模組來組織 | 元件可獨立存在 |
Lazy Loading | 需 RouterModule.forChild() | 直接用 loadComponent() |
效能 (Tree Shaking) | 可能載入不必要的模組 | 只打包需要的部分 |
開發體驗 | 較為繁瑣 | 更靈活、更直覺 |
Tree Shaking 是一種程式碼優化技術,用來移除未使用的程式碼(Dead Code Elimination), 減少最終打包的程式碼大小,提升應用效能。它主要應用在 JavaScript 與 TypeScript 的模組系統(ES6 Modules)。
如何將 NgModule 專案轉移成 Standalone 專案?
Angular 團隊建議使用 Standalone API (Angular v19 官網上的建議)若您的專案預備將之轉移成 Standalone 專案模式,那麼可以使用下面這個指令:
ng generate @angular/core:standalone
首先,它會要求您選擇要遷移的類型,有三個選項:
- Convert all components, directives and pipes to standalone
轉換專案中所有的 component、directive以及 pipe 檔案為Standalone
- Remove unnecessary NgModule classes
刪除 NgModule的類別檔
- Bootstrap the application using standalone APIs
使用 Standalone API 啟動應用程式
使用上下按鈕選擇,遷移程序總共要執行三次,按次序選擇項目。

接下來會詢問「Which path in your project should be migrated」,若已經在專案資料夾可以直接按 「Enter」鍵。

執行完成之後,重複執行上一個指令,選第二項,完成之後再重複,選第三項即可完成遷移行動。

下圖是專案檔在完成遷移之後所更新的檔案 app.component.* 、main.ts 已經變更,app.module.ts 被刪除。

這是遷移之後變更的 main.ts 程式碼:
Main.ts import { importProvidersFrom } from '@angular/core'; import { AppComponent } from './app/app.component'; import { BrowserModule, bootstrapApplication } from '@angular/platform-browser'; bootstrapApplication(AppComponent, { providers: [importProvidersFrom(BrowserModule)] }) .catch(err => console.error(err));
這是遷移之後變更的 app.component.ts 程式碼:
app.component.ts @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], standalone: true, imports: [NgSwitch, NgSwitchDefault, NgSwitchCase] }) export class AppComponent { title = 'ngApp'; }
在@Component 中使用 standalone 宣告這個元件使用 standalone 模式,使用 imports 宣告匯入元件所需用的其他元素。本範例是建構在 Version 18 之下,在 Version 19 之中已經可以不需要明確的使用 standalone 宣告,預設就是 standalone 的元件。
Version 19 不需要明確的使用 standalone 宣告,預設就是 standalone 的元件
新的控制流程@for 、 @if...
Angular 指令 (Directives) 是用在 HTML Template 中在執行階段用來解析與渲染內容的指令,包含 *ngFor 、 *ngIf 、 *ngSwitch …, 以下是 *ngFor 的例子:
<div *ngFor="let item of items; let i = index"> {{ i }} - {{ item }} </div>
以下是 *ngIf 的例子:
<div *ngIf="isLoggedIn; else loginTemplate"> 歡迎回來! </div> <ng-template #loginTemplate> <div>請登入</div> </ng-template>
以下是 *ngSwitch 的例子:
<div [ngSwitch]="status"> <p *ngSwitchCase="'success'">✅ 操作成功!</p> <p *ngSwitchCase="'error'">❌ 發生錯誤,請重試。</p> <p *ngSwitchCase="'pending'">⏳ 處理中,請稍候...</p> <p *ngSwitchDefault>⚠️ 未知狀態。</p> </div>
為什麼 Angular 需要改為@結構式語法
Angular 17推出了 @for 、@if、@switch … 來取代傳統的 *ngFor 、 *ngIf 、 *ngSwitch (*ngXXX 指令仍可使用,Angular 並未提出何時會淘汰)。
-
效能問題:
- *ngFor 需要動態解析範本 (TemplateRef),在變更檢測(Change Detection)時會重新評估所有的 DOM 結構。
- *ngIf 會影響渲染的時機,可能造成不必要的變更檢測。
-
語法較為冗長:
- 需要 let 來定義變數,如 let item of items; let i = index。
- 不能在 ng-container 內直接使用。
-
編譯時無法最佳化:
- *ngFor 和 *ngIf 都是在運行時決定是否渲染,影響效能。
- @for 和 @if 讓控制流變成編譯時決定,減少運行時開銷。
改成@結構式語法的優勢
舊語法 (*ngFor, *ngIf) | 新語法 (@for, @if) | |
---|---|---|
執行時機 | 運行時(Runtime) | 編譯時(Compile-time) |
效能 | 每次變更時需重新解析 | 更少變更檢測、速度更快 |
語法簡潔性 | 需要 *,寫法冗長 | 更直覺、更易讀 |
變數作用域 | 需要 let 來定義 | 內建 index, first, last 變數 |
以下是 @for 的例子:
<ul> @for (item of items; track item.id) { <li>{{ item.id }} - {{ item.name }}</li> } </ul>
以下是 @if 的例子:
@if (isLoggedIn) { <div>歡迎回來! </div> } @else { <div>請登入</div> }
以下是 @switch 的例子:
@switch (status) { @case ('success') { <p>✅ 操作成功!</p> } @case ('error') { <p>❌ 發生錯誤,請重試。</p> } @case ('pending') { <p>⏳ 處理中,請稍候...</p> } @default { <p>⚠️ 未知狀態。</p> } }
什麼是Signals?
在傳統的 Angular 應用程式中,當資料發生變更時,Angular 會執行變更偵測,以檢查所有繫結的屬性並更新 DOM。這個過程可能會很耗時,特別是當應用程式很大且有很多繫結的時候。
此外,即使只有一小部分資料發生變更,Angular 仍然需要檢查整個元件樹,這可能會導致不必要的效能耗費。
於是Angular 18推出了Signals,目的是為了解決傳統變更偵測所帶來的效能挑戰,它是一個新的反應式技術,能更精確的追蹤資料變更,並僅在必要時更新 DOM。
以下是 Angular Signals 的主要優勢:
-
更精確的變更偵測:
Signals 允許追蹤個別屬性的變更,而不是整個元件樹。這意味著只有在實際變更的屬性才會觸發更新,從而減少了不必要的計算。
-
更高的效能:
由於 Signals 只更新必要的 DOM 元素,因此可以提高應用程式的效能,特別是在處理大量資料和複雜繫結時。
-
更簡潔的程式碼:
Signals 可以讓您的程式碼更簡潔,因為不需要手動管理變更偵測。
-
更好的除錯體驗:
Signals 可以讓您更容易追蹤資料變更,從而更容易找到和修復錯誤。
Angular Signals 的核心概念是「信號 (signal)」。信號是一個包含值的物件,您可以讀取和寫入該值。當您寫入一個信號時,它會通知所有訂閱者該值已變更。 在 Angular 中,您可以使用信號來繫結元件的屬性。當信號的值變更時,Angular 會自動更新 DOM。
下面是關於 signal 的一個簡單的範例:
首先,建立一個範例專案,在終端機執行以下命令:
ng new SignalDemo --minimal
- --minimal,最小化應用程式專案,會生成最少依賴項和配置的應用程式。元件將使用Inline Template、Inline Style 方式建立。
接著打開 app.component.ts ,編輯程式碼如下:
import { Component, signal } from '@angular/core'; @Component({ selector: 'app-root', imports: [], template: ` <h1>Welcome to {{title}}!</h1> <p>目前時間: {{ currentTime() }}</p> `, styles: [], }) export class AppComponent { title = 'SignalDemo'; currentTime = signal(new Date().toLocaleTimeString()); constructor() { setInterval(() => { this.currentTime.set(new Date().toLocaleTimeString()); }, 1000); } }
- 這個範例是使用 Angular 19 寫的,所以在 @Component 中已經省略了 standalone: true 的宣告了。
- 使用 signal () 宣告變數並將目前最新的時間放在 signal () 參數之中
currentTime = signal(new Date().toLocaleTimeString());
- 使用 set() 改變變數值,當 setInterval() 的每秒鐘到的時候會將最新的時間填入 signal 。
this.currentTime.set(new Date().toLocaleTimeString());
- 將signal變數呈現於網頁,注意,有別於一般變數,這裡需要使用 () ,像是呼叫函式一樣以取得其值。
<p>目前時間: {{ currentTime() }}</p>
- 使用終端機啟動應用程式:
ng s -o
- 執行結果如下:每秒將會跳動最新的時間。
隨著 Standalone API、@控制流 (@if、@for 等) 以及 Signal 的引入,Angular 在效能優化與開發體驗提升上邁出了關鍵一步。
- Standalone API 簡化了模組管理,使應用架構更靈活、更直覺。
- @控制流 取代傳統的 *ngIf、*ngFor、*ngSwitch語法更貼近原生 JavaScript,且渲染效能更佳。
- Signal 帶來更高效的狀態管理方式,避免不必要的變更偵測,提升應用效能與響應性。
這些改進讓 Angular 更符合現代開發趨勢,讓開發者能夠撰寫更精簡、效能更佳的前端應用。如果您還沒開始使用這些新特性,現在正是最佳時機。
值得一提的是,Angular 仍然保持對舊版語法的相容性,這意味著現有專案不會受到影響,開發者可以逐步採用 Standalone API、@控制流 及 Signal,而無需擔心破壞既有程式碼。Angular 官方也持續提供長期支援 (LTS) 與漸進式升級策略,確保開發團隊可以在適合的時機無縫轉換到新架構。
若您對於學習Angular有更多的興趣,歡迎參考恆逸教育訓練中心Angular課程可以了解更多的技巧喔!