在之前的Angularv15中,Angular團(tuán)隊通過將獨立API從開發(fā)者預(yù)覽版升級至穩(wěn)定版,在Angular的簡易性和開發(fā)者體驗方面達(dá)到了一個重要的里程碑。如今,Angular將繼續(xù)這一改進(jìn)的勢頭,發(fā)布了自Angular最初推出以來最大的一次版本更新;在Reactivity、服務(wù)器端渲染和工具方面取得了巨大的飛躍。
一,重新思考響應(yīng)式Reactivity
作為v16版本的一部分,Angular帶來了全新的Reactivity模型的開發(fā)者預(yù)覽,它為性能和開發(fā)者體驗帶來了顯著的改進(jìn)。完全向后兼容并可與當(dāng)前系統(tǒng)互操作的,并且提供了如下的一些功能:
- 通過減少變化檢測過程中的計算次數(shù),提高運行時的性能。
- 為Reactivity帶來了更簡單的mental模型,使其清楚地了解視圖的依賴性和通過應(yīng)用程序的數(shù)據(jù)流。
- 啟用細(xì)粒度的Reactivity,在未來的版本中,它將允許我們只檢查受影響組件的變化。
- 在未來的版本中,通過使用Signals在模型發(fā)生變化時通知框架,使Zone.js成為可選的。
- 提供計算屬性,而不會在每個變化檢測周期中重新計算。
- 實現(xiàn)了更好的與RxJS的互操作性。
1.1AngularSignals
AngularSignals庫允許你定義Reactive值并表達(dá)它們之間的依賴關(guān)系。你可以在相應(yīng)的RFC中了解更多關(guān)于庫的特性。下面是一個如何將其與Angular一起使用的簡單示例:
@Component({
selector: 'my-app',
standalone: true,
template: `
{{ fullName() }} <button (click)="setName('John')">Click</button>
`,
})
export class App {
firstName = signal('Jane');
lastName = signal('Doe');
fullName = computed(() => `${this.firstName()} ${this.lastName()}`);
constructor() {
effect(() => console.log('Name changed:', this.firstName()));
}
setName(newName: string) {
this.firstName.set(newName);
}
}
如上代碼段創(chuàng)建了一個計算屬性值fullName,它依賴firstName和lastNamesignals,我們也聲明了一個effect,它的回調(diào)函數(shù)將會在其讀取的信號值每次更新時執(zhí)行,也就是firstName更改時重新執(zhí)行,以上的fullName計算屬性意味著它會依賴firstName和lastName信號值的變化。當(dāng)我們設(shè)置firstName為"John"時,瀏覽器會打印如下的日志:
"Namechanged:JohnDoe"
1.2RxJS互操作性
你將能夠通過@angular/core/rxjs-interop中的函數(shù)輕松地將signals轉(zhuǎn)換為observables,該函數(shù)作為v16開發(fā)預(yù)覽版中的一部分。例如,下面是如何轉(zhuǎn)換signal為observable的示例:
import { toObservable, signal } from '@angular/core/rxjs-interop';
@Component({...})
export class App {
count = signal(0);
count$ = toObservable(this.count);
ngOnInit() {
this.count$.subscribe(() => ...);
}
}
下面是一個如何將observable的轉(zhuǎn)換為signal以避免使用async管道的示例:
import {toSignal} from '@angular/core/rxjs-interop';
@Component({
template: `
<li *ngFor="let row of data()"> {{ row }} </li>
`
})
export class App {
dataService = inject(DataService);
data = toSignal(this.dataService.data$, []);
}
Angular用戶通常希望在相關(guān)Subject完成時完成一個流,以下模式非常常見:
destroyed$ = new ReplaySubject<void>(1);
data$ = http.get('...').pipe(takeUntil(this.destroyed$));
ngOnDestroy() {
this.destroyed$.next();
}
接下來,我們介紹一種新的RxJS操作符takeUntilDestroyed,簡單使用示例如下:
data$=http.get('…').pipe(takeUntilDestroyed());
默認(rèn)情況下,此操作符將注入當(dāng)前的清理上下文。假如在組件中使用,它將使用組件的生命周期。當(dāng)你想要將Observable的生命周期與特定組件的生命周期聯(lián)系起來時,takeUntilDestroy特別有用。而takeUntilDestroy是基于下文的DestroyRef實現(xiàn)的。
1.3signals下一階段
接下來我們將研究基于信號組件,信號組件將會簡化生命周期鉤子函數(shù)以及一種簡單的聲明式輸入(inputs)和輸出(outputs),我們還將編寫一套更完整的示例和文檔。
Angular倉儲中最受歡迎的Issue是“Proposal:InputasObservable”。幾個月前,我們回應(yīng)說要支持這個特性為框架的一部分,我們很高興與大家分享,今年晚些時候,我們將推出一項功能,該功能將啟用基于信號的輸入——你將能夠通過interop包將輸入轉(zhuǎn)換為可觀測值。
二、服務(wù)器端渲染和hydration增強(qiáng)
根據(jù)Angular的年度開發(fā)者調(diào)查,服務(wù)器端渲染是Angular的第一大改進(jìn)方向。在過去的幾個月里,Angular與ChromeAurora團(tuán)隊合作,改善了hydration和服務(wù)器端渲染的性能和DX。今天,Angular帶來了完整應(yīng)用非破壞性hydration的開發(fā)者預(yù)覽。
在新的完整應(yīng)用非破壞性 hydration 中,Angular 不再從頭開始重新渲染應(yīng)用。相反,該框架在構(gòu)建內(nèi)部數(shù)據(jù)結(jié)構(gòu)時查找現(xiàn)有的 DOM 節(jié)點,并將事件監(jiān)聽器附加到這些節(jié)點上。這么做的好處是:
- 對終端用戶來說,頁面上沒有內(nèi)容的閃爍。
- 在某些情況下有更好的 Web Core Vitals。
- 面向未來的架構(gòu),可以用我們今年晚些時候推出的基元實現(xiàn)細(xì)粒度的代碼加載。
- 只需幾行代碼就能與現(xiàn)有的應(yīng)用程序輕松集成。
- 對于執(zhí)行手動 DOM 操作的組件,在模板中使用 ngSkipHydration 屬性逐步采用 hydration。
在早期測試中,我們看到 Largest Contentful Paint 通過全應(yīng)用程序 Hydration 作用提高了45%。一些應(yīng)用已經(jīng)在生產(chǎn)中實現(xiàn)了 Hydration,并報告了 CWV 的改進(jìn):開始體驗只需要在main.ts中添加如下幾行代碼即可。
import {
bootstrapApplication,
provideClientHydration,
} from '@angular/platform-browser';
...
bootstrapApplication(RootCmp, {
providers: [provideClientHydration()]
});
2.1 新的服務(wù)器端渲染特性
作為 v16 版本的一部分,我們還更新了 Angular Universal 的 ng-add 原理圖,使你能夠使用獨立 API 將服務(wù)器端渲染添加到項目中。我們還為內(nèi)聯(lián)樣式引入了對更嚴(yán)格的 內(nèi)容安全策略的支持。
2.2 Hydration 和服務(wù)端渲染的下一步
v16 中的工作只是一塊墊腳石,我們計劃在這里做更多的工作。在某些情況下,有機(jī)會延遲加載對頁面不重要的 JavaScript,并在以后對相關(guān)組件進(jìn)行 Hydrate。這種技術(shù)被稱為部分 Hydrate,我們將在下一步對其進(jìn)行探索。
自從 Qwik 從谷歌的封閉源代碼框架 Wiz 中推廣了可恢復(fù)性的想法以來,我們在 Angular 中收到了許多關(guān)于這一功能的請求??苫謴?fù)性肯定在我們的路線圖上,我們正在與 Wiz 團(tuán)隊密切合作,探索更多的空間。我們對它所帶來的開發(fā)人員體驗的限制持謹(jǐn)慎態(tài)度,評估不同的權(quán)衡,并將在我們?nèi)〉眠M(jìn)展時隨時向你通報。
你可以通過閱讀 “What’s next for server-side rendering in Angular” 查看更多未來的計劃。
三、改進(jìn)對獨立組件/指令/管道的工具
Angular 是一個被數(shù)百萬開發(fā)人員用于許多關(guān)鍵使命的應(yīng)用程序框架,我們認(rèn)真對待重大變更,我們 幾年前 就開始探索獨立的 APIs,2022 年我們在開發(fā)者預(yù)覽下發(fā)布了它們,現(xiàn)在,經(jīng)過一年多的收集反饋和對 APIs 的迭代,我們希望被更廣泛的采用!
為了支持開發(fā)人員將其應(yīng)用程序轉(zhuǎn)換為獨立 APIs,我們開發(fā)了遷移原理圖和獨立組件遷移指南,你進(jìn)入項目執(zhí)行如下命令:
ng generate @angular/core:standalone
原理圖將轉(zhuǎn)換你的代碼,刪除不必要的 NgModules類,最后將項目的引導(dǎo)程序更改為使用獨立的 APIs。
3.1 獨立ng new集
作為 Angular v16 的一部分,你可以一開始就創(chuàng)建一個新的獨立項目,要嘗試獨立 APIs 原理圖的開發(fā)預(yù)覽版,請確保你在 Angular CLI v16 上并運行:
ng new --standalone
你將在沒有任何NgModules的情況下獲得更簡單的項目目錄,此外,項目中的所有生成器都將生成獨立的指令、組件和管道。
3.2 配置 Zone.js
在獨立 APIs 首次發(fā)布后,我們從開發(fā)人員那里聽說,希望能夠使用新的 bootstrapApplication API 來配置 Zone.js。我們通過 provideZoneChangeDetection 添加了一些選項:
bootstrapApplication(App, {
providers: [provideZoneChangeDetection({ eventCoalescing: true })]
});
3.3 基于 esbuild 的構(gòu)建系統(tǒng)的開發(fā)預(yù)覽版
一年多前,我們宣布正在 Angular CLI 中對 esbuild 進(jìn)行實驗性支持,以加快構(gòu)建速度。今天,我們很高興與大家分享,在 v16 中,我們基于 esbuild 的構(gòu)建系統(tǒng)進(jìn)入了開發(fā)預(yù)覽版! 早期測試顯示,冷生產(chǎn)環(huán)境構(gòu)建改善了 72% 以上。
在 ng serve 中,我們現(xiàn)在使用 Vite 作為開發(fā)服務(wù)器,esbuild 提供在開發(fā)和生產(chǎn)環(huán)境的構(gòu)建。
我們想強(qiáng)調(diào)的是,Angular CLI 完全依賴 Vite 作為開發(fā)服務(wù)器。為了支持選擇器匹配,Angular 編譯器需要維護(hù)組件之間的依賴關(guān)系圖,這需要與 Vite 不同的編譯模型。你可以通過更新 angular.json 來嘗試 Vite + esbuild :
...
"architect": {
"build": { /* Add the esbuild suffix */
"builder": "@angular-devkit/build-angular:browser-esbuild",
...
接下來,在我們將這一特性從開發(fā)者預(yù)覽提升到正式版之前,我們將解決對 i18n 的支持問題。
3.4 自動完成模板中的導(dǎo)入
你使用模板中的組件或管道從 CLI 或語言服務(wù)中獲得錯誤的次數(shù)是多少次,而實際上沒有導(dǎo)入相應(yīng)的實現(xiàn)?我猜應(yīng)該是很多次。語言服務(wù)現(xiàn)在允許自動導(dǎo)入組件和管道。
如上動圖顯示了 VSCode 中 Angular 語言服務(wù)的自動導(dǎo)入功能。
四、改善開發(fā)者體驗
除了我們重點關(guān)注的大型計劃外,我們還致力于引入備受要求的功能。
4.1 輸入必填(Required inputs)
自從我們在 2016 年引入 Angular 以來,如果不為特定輸入指定值,就不可能出現(xiàn)編譯時錯誤。由于 Angular 編譯器在構(gòu)建時執(zhí)行檢查,因此此更改在運行時增加了零開銷,多年來,開發(fā)人員一直在要求這個功能,我們得到了一個強(qiáng)有力的指示,這將非常方便!在 v16 中,可以根據(jù)需要標(biāo)記輸入為 required :
@Component(...)
export class App {
@Input({ required: true }) title: string = '';
}
4.2 將路由器數(shù)據(jù)作為組件輸入進(jìn)行傳遞
路由的開發(fā)經(jīng)驗一直在快速發(fā)展,GitHub 上一個 流行的功能請求 是要求能夠?qū)⒙酚蓞?shù)綁定到相應(yīng)組件的輸入。我們很高興與大家分享這一功能現(xiàn)已作為 v16 版本的一部分提供?,F(xiàn)在,可以將以下數(shù)據(jù)傳遞給路由組件的輸入:
- 路由 data — resolvers 和 data 屬性
- Path 參數(shù)
- Query 參數(shù)
以下是如何訪問路由 resolver 數(shù)據(jù)的示例:
const routes = [
{
path: 'about',
loadComponent: import('./about'),
resolve: { contact: () => getContact() }
}
];
@Component(...)
export class About {
// The value of "contact" is passed to the contact input
@Input() contact?: string;
}
4.3 CSP 對內(nèi)聯(lián)樣式的支持
Angular 在組件樣式的 DOM 中包含的內(nèi)聯(lián)樣式元素違反了默認(rèn) style-src 內(nèi)容安全策略(CSP) 。要解決此問題,它們應(yīng)該包含一個 nonce 屬性,或者服務(wù)器應(yīng)該在 CSP 頭中包含樣式內(nèi)容的哈希。盡管在谷歌,我們沒有發(fā)現(xiàn)針對該漏洞的有意義的攻擊向量,但許多公司實施了嚴(yán)格的 CSP,導(dǎo)致 Angular 倉儲上的 功能請求 廣受歡迎。
在 Angular v16 中,我們實現(xiàn)了一個跨越框架、Universal、CDK、Material 和 CLI 的新功能,該功能允許你為 Angular 內(nèi)聯(lián)的組件的樣式指定 nonce 屬性。有兩種方法可以指定 nonce:使用 ngCspNonce 屬性或通過 CSP_NONCE 注入令牌。
如果您有權(quán)訪問服務(wù)器端模板,則 ngCspNonce 屬性非常有用,該模板可以在構(gòu)造響應(yīng)時將 nonce 添加到標(biāo)頭和 index.html 中。
<html>
<body>
<app ngCspNonce="{% nonce %}"></app>
</body>
</html>
另一種方法是通過CSP_NONCE注入令牌指定 nonce。如果你在運行時可以訪問 nonce,并且希望能夠緩存 index.html,請使用此方法:
import {bootstrapApplication, CSP_NONCE} from '@angular/core';
import {AppComponent} from './app/app.component';
bootstrapApplication(AppComponent, {
providers: [{
provide: CSP_NONCE,
useValue: globalThis.myRandomNonceValue
}]
});
4.4 靈活的 ngOnDestroy
Angular 的 Lifecycle Hooks 提供了大量的功能,可以插入應(yīng)用程序執(zhí)行的不同時刻,如何實現(xiàn)更高的靈活性是一種機(jī)會和選擇,例如,提供對 OnDestroy as an observable 訪問作為一種可觀察的方式。
在 v16 中,我們使 OnDestroy 可以被注入,此功能實現(xiàn)了開發(fā)人員一直要求的靈活性。新功能允許你注入與組件、指令、服務(wù)或管道相對應(yīng)的DestroyRef ,并注冊onDestroy 生命周期鉤子函數(shù)。DestroyRef 可以被注入到注入上下文中的任何位置,包括組件之外 —— 在這種情況下,當(dāng)相應(yīng)的注入器被銷毀時,ngDestroy 鉤子就會被執(zhí)行:
import { Injectable, DestroyRef } from '@angular/core';
@Injectable(...)
export class AppService {
destroyRef = inject(DestroyRef);
destroy() {
this.destroyRef.onDestroy(() => /* cleanup */ );
}
}
4.5 自動關(guān)閉標(biāo)簽 (Self-closing tags)
我們最近實現(xiàn)的一個 備受要求的功能 ,允許你對 Angular 模板中的組件使用自閉標(biāo)簽,這是一個小的開發(fā)體驗改進(jìn),可以為你節(jié)省一些打字時間。比如:
<super-duper-long-component-name [prop]="someVar"></super-duper-long-component-name>
//替換為
<super-duper-long-component-name [prop]="someVar" />
4.6 更好、更靈活的組件
在過去的幾個季度里,我們與谷歌的 Material Design 團(tuán)隊密切合作,為 Angular Material 的 Web 提供了 Material 3 實現(xiàn)。我們在 2022 年交付的基于 MDC Web 的組件為這項工作奠定了基礎(chǔ)。
作為下一步,我們正在努力在今年晚些時候推出一個基于 expressive token-based 的主題化 API,該 API 支持 Angular Material 組件的更高定制。
提醒一下,我們將在 v17 中刪除遺留的、非基于 MDC 的組件,請確保你按照我們的 遷移指南 進(jìn)行遷移,以獲得最新版本。
參考文檔:文章來源:http://www.zghlxwxcb.cn/news/detail-473053.html
https://blog.angular.io/angular-v16-is-here-4d7a28ec680d文章來源地址http://www.zghlxwxcb.cn/news/detail-473053.html
到了這里,關(guān)于Angular 16 正式版發(fā)布的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!