> [!caution] > ここに記載された内容は再現性が怪しいので参考程度にすること。また、推奨は[[#極力リスクを回避する方法]]の実施 ## バージョン [[Chokidar (JavaScript)|Chokidar]] 3.5.2。 ## 一般的な挙動 ### 監視ディレクトリを削除したとき ```ts import chokidar from "chokidar"; chokidar.watch("target", { ignoreInitial: true }).on("all", (event, path) => { console.log(event, path); }); ``` #### targetディレクトリを作っておく ```console mkdir target npm run dev ``` 監視ディレクトリを一度削除してしまったら、**再生成しても監視対象に追加はされない。** ```bash $ cd target $ touch hoge # add target\hoge $ rm hoge # unlink target\hoge $ cd .. $ rm -rf target # この時点でプログラムが終了した ( = chokidarの監視が終わった) ``` #### targetディレクトリは作っておかない ```console npm run dev ``` この場合は、**ディレクトリを削除しても再生成すれば監視対象に戻る。** ```bash $ mkdir target # addDir target $ cd target $ touch hoge # add target\hoge $ cd .. $ rm -rf target # unlinkDir c:\Users\tadashi-aikawa\tmp\chokidar\target # unlink target\hoge $ mkdir target # addDir target ``` ### 監視ファイルを削除したとき 予めファイルが存在する/しないに関わらず、**削除しても再生成すれば監視対象に戻る。** ## ネストするケース ```ls:初期状態  . └──  data └──  dir └──  target.txt ``` 以下の操作を行った結果を見る。 1. `dir`ディレクトリの削除 2. `dir`ディレクトリの作成 3. `target.txt`の再生成 4. `target.txt`の更新 ```bash [~/data] $ rm -rf dir [~/data] $ mkdir dir [~/data] $ touch dir/target.txt [~/data] $ echo hoge >> dir/target.txt ``` ### dir内のファイルを監視 ```ts import chokidar from "chokidar"; chokidar .watch("sandbox/data/dir/target.txt", { ignoreInitial: true }) .on("all", (event, path) => { console.log("[🗄️target.txt]", event, path); }); ``` ディレクトリ削除でファイルの監視は切れるが、==再度生成しても監視は再開されない。== ```bash [~/data] $ rm -rf dir # [🗄️target.txt] unlink sandbox\data\dir\target.txt [~/data] $ mkdir dir [~/data] $ touch dir/target.txt # 反応なし [~/data] $ echo hoge >> dir/target.txt # 反応なし ``` ### dataディレクトリを監視 ```ts import chokidar from "chokidar"; chokidar .watch("sandbox/data", { ignoreInitial: true }) .on("all", (event, path) => { console.log(event, path); }); ``` 期待通り動く。 ```bash [~/data] $ rm -rf dir # unlinkDir c:\Users\tadashi-aikawa\tmp\chokidar\sandbox\data\dir # unlink sandbox\data\dir\target.txt [~/data] $ mkdir dir # addDir sandbox\data\dir [~/data] $ touch dir/target.txt # add sandbox\data\dir\target.txt [~/data] $ echo hoge >> dir/target.txt # change sandbox\data\dir\target.txt ``` ### dataディレクトリとdir内のファイルを同時監視 ```ts import chokidar from "chokidar"; chokidar .watch("sandbox/data/dir/target.txt", { ignoreInitial: true, }) .on("all", (event, path) => { console.log("[🗄️target.txt]", event, path); }); chokidar .watch("sandbox/data", { ignoreInitial: true }) .on("all", (event, path) => { console.log("[📁data]", event, path); }); ``` 監視状態はこう。 ```ls:監視状態  . └──  data <=== 監視 └──  dir └──  target.txt <=== 監視 ``` [[#dataディレクトリを監視]]したときとは異なり、==監視ファイルを含むディレクトリを削除したとき、再生成したファイルのchangeが検知されない==。 ```bash [~/data] $ rm -rf dir # [📁data] unlinkDir c:\Users\tadashi-aikawa\tmp\chokidar\sandbox\data\dir # [🗄️target.txt] unlink sandbox\data\dir\target.txt # [📁data] unlink sandbox\data\dir\target.txt [~/data] $ mkdir dir # [📁data] addDir sandbox\data\dir [~/data] $ touch dir/target.txt # [📁data] add sandbox\data\dir\target.txt [~/data] $ echo hoge >> dir/target.txt # 何も表示されない。。 ``` ## 対策 2つほど。 ### pollingを使う `usePolling: true`を指定する。 ```ts import chokidar from "chokidar"; chokidar .watch("sandbox/data/dir/target.txt", { ignoreInitial: true, usePolling: true, }) .on("all", (event, path) => { console.log("[🗄️target.txt]", event, path); }); chokidar .watch("sandbox/data", { ignoreInitial: true, usePolling: true }) .on("all", (event, path) => { console.log("[📁data]", event, path); }); ``` ```bash [~/data] $ rm -rf dir # [🗄️target.txt] unlink sandbox\data\dir\target.txt # [📁data] unlink sandbox\data\dir\target.txt # [📁data] unlinkDir sandbox\data\dir [~/data] $ mkdir dir # [📁data] addDir sandbox\data\dir [~/data] $ touch dir/target.txt # [📁data] add sandbox\data\dir\target.txt [~/data] $ echo hoge >> dir/target.txt # [📁data] change sandbox\data\dir\target.txt ``` なお、**どちらか片方をpollingにするだけ**でも検知できた。ただし、==ファイル検知は復活しない。== #### リスク [公式のREADME]にコメントがあるとおりパフォーマンスとの引き換えになる。 [公式のREADME]: https://github.com/paulmillr/chokidar#how > On most other platforms, the fs.watch-based implementation is the default, which avoids polling and keeps CPU usage down. Be advised that chokidar will initiate watchers recursively for everything within scope of the paths that have been specified, so be judicious about not wasting system resources by watching much more than needed `interval`を延ばせば少しは軽減できるものの、==特殊な状況でなければpollingを使うのは避けた方がいい。== ### ignoreInitialをtrueにしない 起動時に`add`や`addDir`イベントが発生するのが嫌だったが、`ignoreInitial: true`にしなければそもそも問題なかった。 開幕の`add`や`addDir`イベントを許容出来ればこれが一番安全そう。 ```ts import chokidar from "chokidar"; chokidar.watch("sandbox/data/dir/target.txt").on("all", (event, path) => { console.log("[🗄️target.txt]", event, path); }); chokidar.watch("sandbox/data").on("all", (event, path) => { console.log("[📁data]", event, path); }); ``` ```bash # [🗄️target.txt] add sandbox\data\dir\target.txt # [📁data] addDir sandbox\data # [📁data] addDir sandbox\data\dir # [📁data] add sandbox\data\dir\target.txt [~/data] $ rm -rf dir # [📁data] unlinkDir sandbox\data\dir # [🗄️target.txt] unlink sandbox\data\dir\target.txt # [📁data] unlink sandbox\data\dir\target.txt [~/data] $ mkdir dir # [📁data] addDir sandbox\data\dir [~/data] $ touch dir/target.txt # [🗄️target.txt] change sandbox\data\dir\target.txt # [📁data] add sandbox\data\dir\target.txt [~/data] $ echo hoge >> dir/target.txt # [🗄️target.txt] change sandbox\data\dir\target.txt # [📁data] change sandbox\data\dir\target.txt ``` ==ただ、ファイル監視(watch)対象が複数になると監視がうまく動かなくなる。。== ## 極力リスクを回避する方法 ### 監視対象ディレクトリおよび監視対象エントリの祖先ディレクトリを削除しない - 📁`parent` - 📁`child` - 📁`grandchild` - 📝`file.txt` とあった場合 - 📁`parent`が監視対象なら - 📁`parent`を削除しない - 📁`child`が監視対象なら - 📁`parent`を削除しない - 📁`child`を削除しない - 📁`grandchild`が監視対象なら - 📁`parent`を削除しない - 📁`child`を削除しない - 📁`grandchild`を削除しない - 📝`file.txt`が監視対象なら - 📁`parent`を削除しない - 📁`child`を削除しない - 📁`grandchild`を削除しない ## 関連Issue - [The watcher does not recognize file changes when the outer directory got deleted once\. · Issue \#1042 · paulmillr/chokidar](https://github.com/paulmillr/chokidar/issues/1042) - [Issue with watching a deleted, then recreated directory · Issue \#917 · paulmillr/chokidar](https://github.com/paulmillr/chokidar/issues/917)