fs-extra vs chokidar vs fsevents vs gaze vs node-watch vs watchpack
Node.js におけるファイルシステム監視と操作ツールの比較
fs-extrachokidarfseventsgazenode-watchwatchpack類似パッケージ:

Node.js におけるファイルシステム監視と操作ツールの比較

chokidarfs-extrafseventsgazenode-watchwatchpack は、Node.js 環境でファイルの変更を検知したり、ファイル操作を簡易化したりするためのライブラリ群です。chokidar はクロスプラットフォームなファイル監視のデファクトスタンダードであり、fs-extra は標準の fs モジュールを拡張して直感的な操作を提供します。fsevents は macOS 専用のネイティブ監視モジュールで、通常は chokidar などの依存関係として利用されます。gazenode-watch は以前広く使われていましたが、現在は保守が停滞しているか、特定の用途に限定されています。watchpack は Webpack 内部で使用される監視ツールで、バンドルツール向けに最適化されています。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
fs-extra75,603,6799,62457.7 kB1219日前MIT
chokidar62,269,27411,96982.1 kB354ヶ月前MIT
fsevents14,060,749567173 kB163年前MIT
gaze1,216,2391,155-688年前MIT
node-watch471,99634126.1 kB83年前MIT
watchpack039795.7 kB132ヶ月前MIT

Node.js におけるファイルシステム監視と操作ツールの比較

Node.js でファイルの変更を検知したり、ファイル操作を自動化したりする際、標準モジュールの fs だけでは不十分な場合があります。chokidarfs-extrafseventsgazenode-watchwatchpack は、それぞれ異なる目的と歴史を持っています。これらがどのように違い、どのように使い分けるべきかを、実際のコードと動作特性から解説します。

📂 基本機能と役割の違い

これらのパッケージは大きく分けて「ファイル監視」と「ファイル操作」の 2 つに分類できます。

chokidar はファイル監視のデファクトスタンダードです。

  • 異なる OS(Windows、macOS、Linux)間で一貫したイベントを提供します。
  • 再帰的な監視や、無視パターンの設定が簡単です。
// chokidar: 基本的な監視
const chokidar = require('chokidar');

const watcher = chokidar.watch('src/**/*.js', {
  ignored: /node_modules/,
  persistent: true
});

watcher.on('change', path => {
  console.log(`File ${path} has been changed`);
});

fs-extra はファイル操作を拡張します。

  • 標準の fs モジュールに、ディレクトリ作成やファイルコピーなどの高レベルな関数を追加します。
  • async/await に対応しており、エラーハンドリングが容易です。
// fs-extra: ディレクトリ確保とファイルコピー
const fs = require('fs-extra');

async function copyAssets() {
  await fs.ensureDir('./dist/assets');
  await fs.copy('./src/assets', './dist/assets');
  console.log('Assets copied successfully');
}

fsevents は macOS 専用のネイティブ監視です。

  • OS のネイティブ API を直接叩くため、macOS 上で非常に高速です。
  • 単独で使うことは少なく、chokidar が内部でオプションとして利用します。
// fsevents: macOS 専用ネイティブ監視(直接使用は稀)
const fsevents = require('fsevents');

const stop = fsevents.watch(__dirname, (path, flags, id) => {
  const info = fsevents.getInfo(path, flags, id);
  console.log('Native event:', info);
});

// 後で停止する場合
// stop();

gaze は古いファイル監視ライブラリです。

  • かつては Grunt などで使われていましたが、現在は保守が停滞しています。
  • Glob パターンに強いですが、現代のプロジェクトでは chokidar への移行が推奨されます。
// gaze: 古い監視ライブラリ(非推奨)
const gaze = require('gaze');

const watcher = new gaze.Gaze('**/*.js');

watcher.on('changed', filepath => {
  console.log(`${filepath} was changed`);
});

node-watchfs.watch のラッパーです。

  • 標準機能の不安定さを吸収しようとしますが、機能は限定的です。
  • 依存関係を減らしたい場合の代替案ですが、chokidar が無難です。
// node-watch: 標準 fs.watch のラッパー
const watch = require('node-watch');

watch('./src', { recursive: true }, (evt, name) => {
  console.log('%s changed.', name);
});

watchpack は Webpack 向けの監視ツールです。

  • 多数のファイルを効率的に監視し、集約されたイベントを発行します。
  • 一般アプリケーションより、ビルドツール開発向きです。
// watchpack: Webpack 内部向け監視
const Watchpack = require('watchpack');

const wp = new Watchpack({
  aggregateTimeout: 1000
});

wp.watch({
  files: ['index.js'],
  directories: ['src']
});

wp.on('aggregated', (changes, removals) => {
  console.log('Changes:', changes);
});

⚙️ 実装アプローチとパフォーマンス

ファイル監視の仕組みは、OS の機能に依存するため、パッケージごとのアプローチが性能に直結します。

chokidar は状況に応じて最適な手法を選びます。

  • macOS では fsevents を使い、Windows では ReadDirectoryChangesW、Linux では inotify を利用します。
  • これにより、CPU 使用率を抑えつつ、見落としを防ぎます。

fsevents はネイティブバインディングです。

  • C++ で書かれたアドオンであり、インストール時にコンパイルが必要です。
  • macOS 以外ではフォールバックが必要になるため、単体利用は困難です。

gazenode-watch は主に fs.watchfs.watchFile に依存します。

  • fs.watchFile はポーリングを行うため、ファイル数が増えると重くなります。
  • 大量のファイルを扱う現代のフロントエンドビルドではボトルネックになり得ます。

watchpack は遅延評価と集約に強いです。

  • 短時間に多数のファイル変更があっても、一度にまとめて処理します。
  • ビルドツールの「リビルド」トリガーとして最適化されています。

🛠️ 実用性とメンテナンス状況

ライブラリを選ぶ際、メンテナンス状況はセキュリティと安定性に直結します。

chokidarfs-extra は活発に保守されています。

  • 最新の Node.js バージョンに対応し、セキュリティ修正も迅速です。
  • 多くの主要フレームワーク(Vite、Parcel など)が内部で採用しています。

gaze は事実上の保守終了状態です。

  • 長期間リリースがなく、現代の Node.js 環境で警告が出る可能性があります。
  • 新規プロジェクトで使う理由はありません。

fsevents は必要な場合にのみインストールされます。

  • optionalDependencies として扱われることが多く、必須ではありません。
  • macOS ユーザーには恩恵がありますが、他 OS では無視されます。

watchpack は Webpack エコシステムに縛られます。

  • Webpack を使わないプロジェクトでわざわざ選ぶメリットは薄いです。
  • 独自のバンドラーを作る場合以外は chokidar で十分です。

🌐 実際のユースケースでの選択

ケース 1: 開発サーバーのホットリロード

ファイル変更を検知してブラウザを更新したい場合。

  • 推奨: chokidar
  • 理由: クロスプラットフォームで安定しており、設定も簡単です。
// chokidar でホットリロード検知
const watcher = chokidar.watch('src');
watcher.on('change', () => {
  reloadBrowser();
});

ケース 2: ビルド成果物の整理

ビルド前にディレクトリを掃除し、ファイルを配置したい場合。

  • 推奨: fs-extra
  • 理由: emptyDirmove などの高機能なメソッドが便利です。
// fs-extra でビルド準備
await fs.emptyDir('./dist');
await fs.move('./temp/build', './dist/final');

ケース 3: 大量のログファイル監視

数千のログファイルの変更を監視したい場合。

  • 推奨: chokidarusePolling: false
  • 理由: ネイティブイベントを使い、パフォーマンスを維持できます。
// chokidar で大量ファイル監視
const watcher = chokidar.watch('/var/logs', {
  usePolling: false,
  interval: 100
});

ケース 4: Webpack プラグイン開発

バンドルプロセス中にファイル変更を捉えたい場合。

  • 推奨: watchpack
  • 理由: Webpack 内部のコンパイルサイクルと統合しやすいです。
// watchpack でプラグイン開発用監視
const wp = new Watchpack();
wp.watch({ files: compiler.inputFiles });

📊 比較サマリー

機能chokidarfs-extrafseventsgazenode-watchwatchpack
主な用途ファイル監視ファイル操作macOS 監視ファイル監視ファイル監視ビルドツール監視
クロスプラットフォーム❌ (macOS only)
保守状況活発活発活発停滞低調活発
ネイティブ依存オプションなし必須なしなしなし
推奨度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐

💡 結論とアドバイス

現代の Node.js 開発において、ファイル監視は chokidar、ファイル操作は fs-extra を選ぶのが最も安全で効率的です。これらはコミュニティでの信頼が厚く、予期せぬトラブルに遭遇するリスクが低いです。

fsevents は意識して選ぶものではなく、chokidar などが勝手に使ってくれるものです。gaze は過去の遺産として扱い、新規採用は避けてください。watchpack は Webpack 関連の特殊な事情がない限り、一般的な用途では chokidar で代用可能です。

最終的な指針:

  • 監視が必要ならchokidar
  • 操作を楽にしたいならfs-extra
  • それ以外 → 標準の fs モジュールで十分

この 2 つを覚えておけば、ほとんどのファイルシステム関連の要件はカバーできます。

選び方: fs-extra vs chokidar vs fsevents vs gaze vs node-watch vs watchpack

  • fs-extra:

    ファイルのコピー、移動、削除などを直感的なメソッドで行いたい場合は fs-extra を使います。標準の fs モジュールに欠けている ensureDircopy などの便利機能が揃っており、エラーハンドリングも親切です。

  • chokidar:

    クロスプラットフォームで安定したファイル監視が必要な場合は chokidar を選択します。Node.js エコシステムで最も広く支持されており、macOS、Windows、Linux で一貫した動作を保証します。新規プロジェクトのファイル監視ではこれが第一選択肢です。

  • fsevents:

    macOS 環境でネイティブなファイルイベント監視を最適化したい場合に使いますが、単独では使いません。通常は chokidar が自動的に利用するため、明示的に導入するケースは稀です。Windows や Linux では動作しないため注意が必要です。

  • gaze:

    古いプロジェクトの保守以外では gaze の使用は避けるべきです。保守が停滞しており、現代の Node.js バージョンとの互換性やパフォーマンス面で chokidar に劣ります。新規プロジェクトでの採用は推奨されません。

  • node-watch:

    Node.js 標準の fs.watch をラップして使いやすくしたい場合に検討しますが、機能面で chokidar に劣ります。依存関係を減らしたい軽量なユースケース以外では、より堅牢な chokidar を選ぶのが無難です。

  • watchpack:

    Webpack プラグインやバンドルツール内部のロジックを構築する場合は watchpack を検討します。一般のアプリケーション開発ではなく、ビルドツール開発など特定のインフラ要件がある場合に適しています。

fs-extra のREADME

Node.js: fs-extra

fs-extra adds file system methods that aren't included in the native fs module and adds promise support to the fs methods. It also uses graceful-fs to prevent EMFILE errors. It should be a drop in replacement for fs.

npm Package License build status downloads per month JavaScript Style Guide

Why?

I got tired of including mkdirp, rimraf, and ncp in most of my projects.

Installation

npm install fs-extra

Usage

CommonJS

fs-extra is a drop in replacement for native fs. All methods in fs are attached to fs-extra. All fs methods return promises if the callback isn't passed.

You don't ever need to include the original fs module again:

const fs = require('fs') // this is no longer necessary

you can now do this:

const fs = require('fs-extra')

or if you prefer to make it clear that you're using fs-extra and not fs, you may want to name your fs variable fse like so:

const fse = require('fs-extra')

you can also keep both, but it's redundant:

const fs = require('fs')
const fse = require('fs-extra')

NOTE: The deprecated constants fs.F_OK, fs.R_OK, fs.W_OK, & fs.X_OK are not exported on Node.js v24.0.0+; please use their fs.constants equivalents.

ESM

There is also an fs-extra/esm import, that supports both default and named exports. However, note that fs methods are not included in fs-extra/esm; you still need to import fs and/or fs/promises seperately:

import { readFileSync } from 'fs'
import { readFile } from 'fs/promises'
import { outputFile, outputFileSync } from 'fs-extra/esm'

Default exports are supported:

import fs from 'fs'
import fse from 'fs-extra/esm'
// fse.readFileSync is not a function; must use fs.readFileSync

but you probably want to just use regular fs-extra instead of fs-extra/esm for default exports:

import fs from 'fs-extra'
// both fs and fs-extra methods are defined

Sync vs Async vs Async/Await

Most methods are async by default. All async methods will return a promise if the callback isn't passed.

Sync methods on the other hand will throw if an error occurs.

Also Async/Await will throw an error if one occurs.

Example:

const fs = require('fs-extra')

// Async with promises:
fs.copy('/tmp/myfile', '/tmp/mynewfile')
  .then(() => console.log('success!'))
  .catch(err => console.error(err))

// Async with callbacks:
fs.copy('/tmp/myfile', '/tmp/mynewfile', err => {
  if (err) return console.error(err)
  console.log('success!')
})

// Sync:
try {
  fs.copySync('/tmp/myfile', '/tmp/mynewfile')
  console.log('success!')
} catch (err) {
  console.error(err)
}

// Async/Await:
async function copyFiles () {
  try {
    await fs.copy('/tmp/myfile', '/tmp/mynewfile')
    console.log('success!')
  } catch (err) {
    console.error(err)
  }
}

copyFiles()

Methods

Async

Sync

NOTE: You can still use the native Node.js methods. They are promisified and copied over to fs-extra. See notes on fs.read(), fs.write(), & fs.writev()

What happened to walk() and walkSync()?

They were removed from fs-extra in v2.0.0. If you need the functionality, walk and walkSync are available as separate packages, klaw and klaw-sync.

Third Party

CLI

fse-cli allows you to run fs-extra from a console or from npm scripts.

TypeScript

If you like TypeScript, you can use fs-extra with it: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/fs-extra

File / Directory Watching

If you want to watch for changes to files or directories, then you should use chokidar.

Obtain Filesystem (Devices, Partitions) Information

fs-filesystem allows you to read the state of the filesystem of the host on which it is run. It returns information about both the devices and the partitions (volumes) of the system.

Misc.

Hacking on fs-extra

Wanna hack on fs-extra? Great! Your help is needed! fs-extra is one of the most depended upon Node.js packages. This project uses JavaScript Standard Style - if the name or style choices bother you, you're gonna have to get over it :) If standard is good enough for npm, it's good enough for fs-extra.

js-standard-style

What's needed?

  • First, take a look at existing issues. Those are probably going to be where the priority lies.
  • More tests for edge cases. Specifically on different platforms. There can never be enough tests.
  • Improve test coverage.

Note: If you make any big changes, you should definitely file an issue for discussion first.

Running the Test Suite

fs-extra contains hundreds of tests.

  • npm run lint: runs the linter (standard)
  • npm run unit: runs the unit tests
  • npm run unit-esm: runs tests for fs-extra/esm exports
  • npm test: runs the linter and all tests

When running unit tests, set the environment variable CROSS_DEVICE_PATH to the absolute path of an empty directory on another device (like a thumb drive) to enable cross-device move tests.

Windows

If you run the tests on the Windows and receive a lot of symbolic link EPERM permission errors, it's because on Windows you need elevated privilege to create symbolic links. You can add this to your Windows's account by following the instructions here: http://superuser.com/questions/104845/permission-to-make-symbolic-links-in-windows-7 However, I didn't have much luck doing this.

Since I develop on Mac OS X, I use VMWare Fusion for Windows testing. I create a shared folder that I map to a drive on Windows. I open the Node.js command prompt and run as Administrator. I then map the network drive running the following command:

net use z: "\\vmware-host\Shared Folders"

I can then navigate to my fs-extra directory and run the tests.

Naming

I put a lot of thought into the naming of these functions. Inspired by @coolaj86's request. So he deserves much of the credit for raising the issue. See discussion(s) here:

First, I believe that in as many cases as possible, the Node.js naming schemes should be chosen. However, there are problems with the Node.js own naming schemes.

For example, fs.readFile() and fs.readdir(): the F is capitalized in File and the d is not capitalized in dir. Perhaps a bit pedantic, but they should still be consistent. Also, Node.js has chosen a lot of POSIX naming schemes, which I believe is great. See: fs.mkdir(), fs.rmdir(), fs.chown(), etc.

We have a dilemma though. How do you consistently name methods that perform the following POSIX commands: cp, cp -r, mkdir -p, and rm -rf?

My perspective: when in doubt, err on the side of simplicity. A directory is just a hierarchical grouping of directories and files. Consider that for a moment. So when you want to copy it or remove it, in most cases you'll want to copy or remove all of its contents. When you want to create a directory, if the directory that it's suppose to be contained in does not exist, then in most cases you'll want to create that too.

So, if you want to remove a file or a directory regardless of whether it has contents, just call fs.remove(path). If you want to copy a file or a directory whether it has contents, just call fs.copy(source, destination). If you want to create a directory regardless of whether its parent directories exist, just call fs.mkdirs(path) or fs.mkdirp(path).

Credit

fs-extra wouldn't be possible without using the modules from the following authors:

License

Licensed under MIT

Copyright (c) 2011-2024 JP Richardson