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
内のパッケージに直接パッチを当てるためのツールです。主に以下のような場合に使用します:
- パッケージのバグを修正したいが、PRがまだマージされていない
- パッケージの機能を拡張したいが、PRがまだマージされていない
- パッケージのバージョンを上げたくないが、特定のバグ修正だけを適用したい
仕組み
patch-package
は、パッケージの修正を一時的に適用するための仕組みを提供します。まず、node_modules
内のパッケージを直接修正し、その変更内容をpatches
ディレクトリに保存します。その後、npm install
を実行すると、postinstall
スクリプトを通じて自動的にパッチが適用されます。
この仕組みにより、パッケージのソースコードを直接修正することなく、一時的な修正を適用することができます。また、パッチファイルはバージョン管理システムで管理できるため、チーム内で同じ修正を共有することも可能です。
実装手順
1. patch-packageのインストール
まず、patch-package
をインストールします:
npm install --save-dev patch-package
2. package.jsonの修正
package.json
のscripts
セクションに以下のスクリプトを追加します:
{
"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など)にコミットすることをお勧めします。これにより、以下のメリットがあります:
- チーム内で同じ修正を共有できる
- パッチの変更履歴を追跡できる
- パッチの適用忘れを防ぐことができる
パッケージのバージョンが上がった場合、パッチが適用できなくなる可能性があります。その場合は、パッチを更新する必要があります。
まとめ
この記事では、Angularのzonelessモードで発生するCDK Virtual Scrollの不具合をpatch-package
を使用して修正する方法を紹介しました。
この修正により、Virtual Scrollのちらつきが解消され、よりスムーズなスクロール体験を提供することができます。
なお、この修正は一時的なものであり、Angularの公式な修正がリリースされた際には、パッチを削除して公式の修正を使用することをお勧めします。
それでは、また。
Discussion