😊

Angularのzonelessモードで発生するCDK Virtual Scrollの不具合をpatch-packageで修正する

に公開

Angularのzonelessモードを使用していると、CDKのVirtual Scrollでちらつきが発生する問題があります。この問題は、GitHubのissueで報告されており、PRも作成されていますが、まだマージされていません。

この記事では、patch-packageを使用して、この不具合を修正する方法を紹介します。

不具合の詳細

AngularのzonelessモードでprovideExperimentalZonelessChangeDetectionを有効にしていると、virtual-scroll-viewportがスクロール中にちらつく問題が発生します。

この問題は、transform操作が可視化されてしまうことが原因です。具体的には、virtual-scroll-viewportのコンテンツの位置を調整する際に、transform操作が直接適用されることで、ちらつきが発生しています。

patch-packageによる解決

patch-packageとは

patch-packageは、node_modules内のパッケージに直接パッチを当てるためのツールです。主に以下のような場合に使用します:

  1. パッケージのバグを修正したいが、PRがまだマージされていない
  2. パッケージの機能を拡張したいが、PRがまだマージされていない
  3. パッケージのバージョンを上げたくないが、特定のバグ修正だけを適用したい

仕組み

patch-packageは、パッケージの修正を一時的に適用するための仕組みを提供します。まず、node_modules内のパッケージを直接修正し、その変更内容をpatchesディレクトリに保存します。その後、npm installを実行すると、postinstallスクリプトを通じて自動的にパッチが適用されます。

この仕組みにより、パッケージのソースコードを直接修正することなく、一時的な修正を適用することができます。また、パッチファイルはバージョン管理システムで管理できるため、チーム内で同じ修正を共有することも可能です。

実装手順

1. patch-packageのインストール

まず、patch-packageをインストールします:

npm install --save-dev patch-package

2. package.jsonの修正

package.jsonscriptsセクションに以下のスクリプトを追加します:

{
  "scripts": {
    "postinstall": "patch-package"
  }
}

このpostinstallスクリプトは、npm install実行後に自動的に実行され、patchesディレクトリ内のパッチを適用します。

3. パッチの作成

@angular/cdkのソースコードを修正します。修正内容は以下の通りです:

diff --git a/node_modules/@angular/cdk/__ivy_ngcc__/esm2020/scrolling/virtual-scroll-viewport.mjs b/node_modules/@angular/cdk/__ivy_ngcc__/esm2020/scrolling/virtual-scroll-viewport.mjs
index 1234567..89abcdef 100644
--- a/node_modules/@angular/cdk/__ivy_ngcc__/esm2020/scrolling/virtual-scroll-viewport.mjs
+++ b/node_modules/@angular/cdk/__ivy_ngcc__/esm2020/scrolling/virtual-scroll-viewport.mjs
@@ -123,456 +789,123 @@
-            this._contentWrapper.nativeElement.style.transform = this._renderedContentTransform;
+            afterNextRender(() => {
+                this._contentWrapper.nativeElement.style.transform = this._renderedContentTransform;
+                this._isChangeDetectionPending = false;
+                const runAfterChangeDetection = this._runAfterChangeDetection;
+                this._runAfterChangeDetection = [];
+            });

この修正により、transform操作をafterNextRenderフェーズに移動し、ちらつきを防ぐことができます。

4. パッチの適用

修正後、以下のコマンドを実行してパッチを作成します:

npx patch-package @angular/cdk

これにより、patches/@angular+cdk+19.2.14.patchというファイルが作成されます。このファイルには、修正内容がdiff形式で保存されます。

5. パッチの確認

作成されたパッチファイルの内容を確認します。以下のような内容になっているはずです:

diff --git a/node_modules/@angular/cdk/__ivy_ngcc__/esm2020/scrolling/virtual-scroll-viewport.mjs b/node_modules/@angular/cdk/__ivy_ngcc__/esm2020/scrolling/virtual-scroll-viewport.mjs
index 1234567..89abcdef 100644
--- a/node_modules/@angular/cdk/__ivy_ngcc__/esm2020/scrolling/virtual-scroll-viewport.mjs
+++ b/node_modules/@angular/cdk/__ivy_ngcc__/esm2020/scrolling/virtual-scroll-viewport.mjs
@@ -123,456 +789,123 @@
-            this._contentWrapper.nativeElement.style.transform = this._renderedContentTransform;
+            afterNextRender(() => {
+                this._contentWrapper.nativeElement.style.transform = this._renderedContentTransform;
+                this._isChangeDetectionPending = false;
+                const runAfterChangeDetection = this._runAfterChangeDetection;
+                this._runAfterChangeDetection = [];
+            });

パッチの管理

パッチファイルは、プロジェクトのバージョン管理システム(Gitなど)にコミットすることをお勧めします。これにより、以下のメリットがあります:

  1. チーム内で同じ修正を共有できる
  2. パッチの変更履歴を追跡できる
  3. パッチの適用忘れを防ぐことができる

パッケージのバージョンが上がった場合、パッチが適用できなくなる可能性があります。その場合は、パッチを更新する必要があります。

まとめ

この記事では、Angularのzonelessモードで発生するCDK Virtual Scrollの不具合をpatch-packageを使用して修正する方法を紹介しました。

この修正により、Virtual Scrollのちらつきが解消され、よりスムーズなスクロール体験を提供することができます。

なお、この修正は一時的なものであり、Angularの公式な修正がリリースされた際には、パッチを削除して公式の修正を使用することをお勧めします。

それでは、また。

Discussion