詳細ガイド
実験的機能

ZoneJSを使わないAngular (Zoneless)

なぜZonelessを使うのか?

ZoneJSを依存関係として削除する主な利点は次のとおりです。

  • パフォーマンスの向上: ZoneJSは、アプリケーションの状態が更新された可能性があるタイミングの指標としてDOMイベントと非同期タスクを使用し、その後、アプリケーションのビューで変更検知を実行するためにアプリケーションの同期をトリガーします。ZoneJSは、アプリケーションの状態が実際に変更されたかどうかを把握していないため、この同期は必要以上に頻繁にトリガーされます。
  • Core Web Vitalsの改善: ZoneJSは、ペイロードサイズと起動時間の両方で、かなりのオーバーヘッドをもたらします。
  • デバッグ体験の向上: ZoneJSは、コードのデバッグをより困難にします。スタックトレースはZoneJSでは理解しにくくなります。また、コードがAngular Zoneの外部にあるために壊れた場合も理解しにくいです。
  • より良いエコシステム互換性: ZoneJSはブラウザAPIをパッチ適用することで動作しますが、すべての新しいブラウザAPIに対して自動的にパッチが適用されるわけではありません。一部のAPIは、async/awaitのように効果的にパッチを適用できず、ZoneJSで動作するようにダウンレベルする必要があります。場合によっては、エコシステム内のライブラリも、ZoneJSがネイティブAPIにパッチを適用する方法と互換性がないことがあります。ZoneJSを依存関係として削除すると、複雑さ、モンキーパッチ、および継続的なメンテナンスのソースが削除されるため、長期的な互換性が向上します。

アプリケーションでZonelessを有効にする

Zonelessを有効にするためのAPIは現在、実験的機能です。その仕様や根本的な挙動は安定しておらず、 パッチバージョンで変更される可能性があります。既知の機能面での不足があり、その一例としてサーバーサイドレンダリングでアプリケーションが早期にシリアライズされるのを防ぐための使いやすいAPIが存在しないことが挙げられます。

      
// スタンドアロン ブートストラップbootstrapApplication(MyApp, {providers: [  provideExperimentalZonelessChangeDetection(),]});// NgModule ブートストラップplatformBrowser().bootstrapModule(AppModule);@NgModule({  providers: [provideExperimentalZonelessChangeDetection()]})export class AppModule {}

ZoneJSの削除

Zonelessアプリケーションは、バンドルサイズを削減するために、ビルドからZoneJSを完全に削除する必要があります。ZoneJSは通常、 angular.jsonpolyfillsオプションを介して、buildtestの両方のターゲットでロードされます。ビルドから削除するには、 両方からzone.jszone.js/testingを削除します。明示的なpolyfills.tsファイルを 使用するプロジェクトは、ファイルからimport 'zone.js';import 'zone.js/testing';を削除する必要があります。

ビルドからZoneJSを削除すると、zone.jsの依存関係も不要になり、 パッケージを完全に削除できます。

      
npm uninstall zone.js

Zoneless互換性の要件

Angularは、変更検知をいつ、どのビューで実行するかを判断するために、コアAPIからの通知に依存しています。 これらの通知には次のものが含まれます。

  • ChangeDetectorRef.markForCheck (AsyncPipeによって自動的に呼び出されます)
  • ComponentRef.setInput
  • テンプレートで読み取られるシグナルの更新
  • バインドされたホストまたはテンプレートリスナーのコールバック
  • 上記のいずれかによってダーティーとしてマークされたビューのアタッチ

OnPush互換コンポーネント

コンポーネントが上記の正しい通知メカニズムを使用していることを確認する1つの方法は、 ChangeDetectionStrategy.OnPushを使用することです。

OnPush変更検知戦略は必須ではありませんが、アプリケーションコンポーネントのZoneless互換性への推奨されるステップです。ライブラリコンポーネントがChangeDetectionStrategy.OnPushを使用することが常に可能であるとは限りません。 ライブラリコンポーネントがChangeDetectionStrategy.Defaultを使用する可能性のあるユーザーコンポーネントのホストである場合、子コンポーネントがOnPush互換ではなく、ZoneJSに依存して変更検知をトリガーする場合、子コンポーネントが更新されなくなるため、OnPushを使用できません。コンポーネントは、変更検知を実行する必要があるときにAngularに通知する限り(markForCheckの呼び出し、シグナルの使用、AsyncPipeなど)、Default戦略を使用できます。

NgZone.onMicrotaskEmptyNgZone.onUnstableNgZone.isStable、またはNgZone.onStableの削除

アプリケーションとライブラリは、NgZone.onMicrotaskEmptyNgZone.onUnstable、およびNgZone.onStableの使用を削除する必要があります。 アプリケーションがZoneless変更検知を有効にすると、これらのObservableは発行されません。 同様に、NgZone.isStableは常にtrueになり、コード実行の条件として使用できません。

NgZone.onMicrotaskEmptyおよびNgZone.onStableのObservableは、多くの場合、タスクを実行する前にAngularが 変更検知を完了するのを待つために最もよく使用されます。代わりに、単一の変更検知を 待つ必要がある場合はafterNextRender、 またはいくつかの変更検知ラウンドにまたがる可能性のある 条件がある場合はafterRenderに置き換えることができます。 他のケースでは、これらのObservableは たまたま馴染みがあり、必要なものと似たタイミングであったために使用されています。 コードが特定のDOM状態を待つ必要がある場合(Angularのレンダリングフックを介して間接的に待つのではなく)、 MutationObserverなど、より簡単または直接的なDOM APIを代わりに使用できます。

NgZone.run and NgZone.runOutsideAngular are compatible with Zoneless

NgZone.runNgZone.runOutsideAngularは、コードをZonelessアプリケーションと互換性を持たせるために 削除する必要はありません。実際、これらの呼び出しを削除すると、ZoneJSに依然として依存しているアプリケーションで使用されるライブラリの パフォーマンスが低下する可能性があります。

サーバーサイドレンダリング(SSR)のPendingTasks

AngularでSSRを使用している場合、アプリケーションが「安定」しており、シリアライズできるかどうかを判断するために、 ZoneJSに依存していることをご存知かもしれません。シリアライズを妨げる非同期タスクがある場合、 ZoneJSを使用していないアプリケーションは、PendingTasksサービスを使用してAngularにこれらを認識させる必要があります。シリアライズは、 保留中のすべてのタスクが削除された最初の瞬間まで待機します。

      
const taskService = inject(PendingTasks);const taskCleanup = taskService.add();await doSomeWorkThatNeedsToBeRendered();taskCleanup();

フレームワークは、非同期タスクが完了するまでシリアライズを防ぐために、このサービスを内部的にも使用します。これには、 進行中のルーターナビゲーションや未完了のHttpClientリクエストが含まれますが、これらに限定されません。

テストとデバッグ

TestBedでZonelessを使用する

Zonelessプロバイダー関数は、TestBedでも使用して、 テスト対象のコンポーネントがZoneless Angularアプリケーションと 互換性があることを確認できます。

      
TestBed.configureTestingModule({  providers: [provideExperimentalZonelessChangeDetection()]});const fixture = TestBed.createComponent(MyComponent);await fixture.whenStable();

テストが本番コードと最も類似した動作をすることを確認するには、 可能な限りfixture.detectChanges()の使用を避けてください。これにより、 Angularが変更検知をスケジュールしていない場合に、 変更検知が強制的に実行されます。テストでは、これらの通知が発生していることを確認し、 手動で強制的に発生させるのではなく、 Angularが状態を同期するタイミングを処理できるようにする必要があります。

更新が検出されることを確認するためのデバッグモードチェック

Angularは、アプリケーションがZoneless互換の方法で状態を更新していることを 確認するのに役立つ追加のツールも提供しています。provideExperimentalCheckNoChangesForDebugを使用すると、 通知なしにバインディングが更新されていないことを定期的に確認できます。 Zoneless変更検知によってリフレッシュされない更新済みバインディングがある場合、 AngularはExpressionChangedAfterItHasBeenCheckedErrorを スローします。