| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- # Chokidar [](https://github.com/paulmillr/chokidar)
- > Minimal and efficient cross-platform file watching library
- ## Why?
- There are many reasons to prefer Chokidar to raw fs.watch / fs.watchFile in 2024:
- - Events are properly reported
- - macOS events report filenames
- - events are not reported twice
- - changes are reported as add / change / unlink instead of useless `rename`
- - Atomic writes are supported, using `atomic` option
- - Some file editors use them
- - Chunked writes are supported, using `awaitWriteFinish` option
- - Large files are commonly written in chunks
- - File / dir filtering is supported
- - Symbolic links are supported
- - Recursive watching is always supported, instead of partial when using raw events
- - Includes a way to limit recursion depth
- Chokidar relies on the Node.js core `fs` module, but when using
- `fs.watch` and `fs.watchFile` for watching, it normalizes the events it
- receives, often checking for truth by getting file stats and/or dir contents.
- 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. For some cases, `fs.watchFile`, which utilizes polling and uses more resources, is used.
- Made for [Brunch](https://brunch.io/) in 2012,
- it is now used in [~30 million repositories](https://www.npmjs.com/browse/depended/chokidar) and
- has proven itself in production environments.
- **Sep 2024 update:** v4 is out! It decreases dependency count from 13 to 1, removes
- support for globs, adds support for ESM / Common.js modules, and bumps minimum node.js version from v8 to v14.
- Check out [upgrading](#upgrading).
- ## Getting started
- Install with npm:
- ```sh
- npm install chokidar
- ```
- Use it in your code:
- ```javascript
- import chokidar from 'chokidar';
- // One-liner for current directory
- chokidar.watch('.').on('all', (event, path) => {
- console.log(event, path);
- });
- // Extended options
- // ----------------
- // Initialize watcher.
- const watcher = chokidar.watch('file, dir, or array', {
- ignored: (path, stats) => stats?.isFile() && !path.endsWith('.js'), // only watch js files
- persistent: true
- });
- // Something to use when events are received.
- const log = console.log.bind(console);
- // Add event listeners.
- watcher
- .on('add', path => log(`File ${path} has been added`))
- .on('change', path => log(`File ${path} has been changed`))
- .on('unlink', path => log(`File ${path} has been removed`));
- // More possible events.
- watcher
- .on('addDir', path => log(`Directory ${path} has been added`))
- .on('unlinkDir', path => log(`Directory ${path} has been removed`))
- .on('error', error => log(`Watcher error: ${error}`))
- .on('ready', () => log('Initial scan complete. Ready for changes'))
- .on('raw', (event, path, details) => { // internal
- log('Raw event info:', event, path, details);
- });
- // 'add', 'addDir' and 'change' events also receive stat() results as second
- // argument when available: https://nodejs.org/api/fs.html#fs_class_fs_stats
- watcher.on('change', (path, stats) => {
- if (stats) console.log(`File ${path} changed size to ${stats.size}`);
- });
- // Watch new files.
- watcher.add('new-file');
- watcher.add(['new-file-2', 'new-file-3']);
- // Get list of actual paths being watched on the filesystem
- let watchedPaths = watcher.getWatched();
- // Un-watch some files.
- await watcher.unwatch('new-file');
- // Stop watching. The method is async!
- await watcher.close().then(() => console.log('closed'));
- // Full list of options. See below for descriptions.
- // Do not use this example!
- chokidar.watch('file', {
- persistent: true,
- // ignore .txt files
- ignored: (file) => file.endsWith('.txt'),
- // watch only .txt files
- // ignored: (file, _stats) => _stats?.isFile() && !file.endsWith('.txt'),
- awaitWriteFinish: true, // emit single event when chunked writes are completed
- atomic: true, // emit proper events when "atomic writes" (mv _tmp file) are used
- // The options also allow specifying custom intervals in ms
- // awaitWriteFinish: {
- // stabilityThreshold: 2000,
- // pollInterval: 100
- // },
- // atomic: 100,
- interval: 100,
- binaryInterval: 300,
- cwd: '.',
- depth: 99,
- followSymlinks: true,
- ignoreInitial: false,
- ignorePermissionErrors: false,
- usePolling: false,
- alwaysStat: false,
- });
- ```
- `chokidar.watch(paths, [options])`
- * `paths` (string or array of strings). Paths to files, dirs to be watched
- recursively.
- * `options` (object) Options object as defined below:
- #### Persistence
- * `persistent` (default: `true`). Indicates whether the process
- should continue to run as long as files are being watched.
- #### Path filtering
- * `ignored` function, regex, or path. Defines files/paths to be ignored.
- The whole relative or absolute path is tested, not just filename. If a function with two arguments
- is provided, it gets called twice per path - once with a single argument (the path), second
- time with two arguments (the path and the
- [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats)
- object of that path).
- * `ignoreInitial` (default: `false`). If set to `false` then `add`/`addDir` events are also emitted for matching paths while
- instantiating the watching as chokidar discovers these file paths (before the `ready` event).
- * `followSymlinks` (default: `true`). When `false`, only the
- symlinks themselves will be watched for changes instead of following
- the link references and bubbling events through the link's path.
- * `cwd` (no default). The base directory from which watch `paths` are to be
- derived. Paths emitted with events will be relative to this.
- #### Performance
- * `usePolling` (default: `false`).
- Whether to use fs.watchFile (backed by polling), or fs.watch. If polling
- leads to high CPU utilization, consider setting this to `false`. It is
- typically necessary to **set this to `true` to successfully watch files over
- a network**, and it may be necessary to successfully watch files in other
- non-standard situations. Setting to `true` explicitly on MacOS overrides the
- `useFsEvents` default. You may also set the CHOKIDAR_USEPOLLING env variable
- to true (1) or false (0) in order to override this option.
- * _Polling-specific settings_ (effective when `usePolling: true`)
- * `interval` (default: `100`). Interval of file system polling, in milliseconds. You may also
- set the CHOKIDAR_INTERVAL env variable to override this option.
- * `binaryInterval` (default: `300`). Interval of file system
- polling for binary files.
- ([see list of binary extensions](https://github.com/sindresorhus/binary-extensions/blob/master/binary-extensions.json))
- * `alwaysStat` (default: `false`). If relying upon the
- [`fs.Stats`](https://nodejs.org/api/fs.html#fs_class_fs_stats)
- object that may get passed with `add`, `addDir`, and `change` events, set
- this to `true` to ensure it is provided even in cases where it wasn't
- already available from the underlying watch events.
- * `depth` (default: `undefined`). If set, limits how many levels of
- subdirectories will be traversed.
- * `awaitWriteFinish` (default: `false`).
- By default, the `add` event will fire when a file first appears on disk, before
- the entire file has been written. Furthermore, in some cases some `change`
- events will be emitted while the file is being written. In some cases,
- especially when watching for large files there will be a need to wait for the
- write operation to finish before responding to a file creation or modification.
- Setting `awaitWriteFinish` to `true` (or a truthy value) will poll file size,
- holding its `add` and `change` events until the size does not change for a
- configurable amount of time. The appropriate duration setting is heavily
- dependent on the OS and hardware. For accurate detection this parameter should
- be relatively high, making file watching much less responsive.
- Use with caution.
- * *`options.awaitWriteFinish` can be set to an object in order to adjust
- timing params:*
- * `awaitWriteFinish.stabilityThreshold` (default: 2000). Amount of time in
- milliseconds for a file size to remain constant before emitting its event.
- * `awaitWriteFinish.pollInterval` (default: 100). File size polling interval, in milliseconds.
- #### Errors
- * `ignorePermissionErrors` (default: `false`). Indicates whether to watch files
- that don't have read permissions if possible. If watching fails due to `EPERM`
- or `EACCES` with this set to `true`, the errors will be suppressed silently.
- * `atomic` (default: `true` if `useFsEvents` and `usePolling` are `false`).
- Automatically filters out artifacts that occur when using editors that use
- "atomic writes" instead of writing directly to the source file. If a file is
- re-added within 100 ms of being deleted, Chokidar emits a `change` event
- rather than `unlink` then `add`. If the default of 100 ms does not work well
- for you, you can override it by setting `atomic` to a custom value, in
- milliseconds.
- ### Methods & Events
- `chokidar.watch()` produces an instance of `FSWatcher`. Methods of `FSWatcher`:
- * `.add(path / paths)`: Add files, directories for tracking.
- Takes an array of strings or just one string.
- * `.on(event, callback)`: Listen for an FS event.
- Available events: `add`, `addDir`, `change`, `unlink`, `unlinkDir`, `ready`,
- `raw`, `error`.
- Additionally `all` is available which gets emitted with the underlying event
- name and path for every event other than `ready`, `raw`, and `error`. `raw` is internal, use it carefully.
- * `.unwatch(path / paths)`: Stop watching files or directories.
- Takes an array of strings or just one string.
- * `.close()`: **async** Removes all listeners from watched files. Asynchronous, returns Promise. Use with `await` to ensure bugs don't happen.
- * `.getWatched()`: Returns an object representing all the paths on the file
- system being watched by this `FSWatcher` instance. The object's keys are all the
- directories (using absolute paths unless the `cwd` option was used), and the
- values are arrays of the names of the items contained in each directory.
- ### CLI
- Check out third party [chokidar-cli](https://github.com/open-cli-tools/chokidar-cli),
- which allows to execute a command on each change, or get a stdio stream of change events.
- ## Troubleshooting
- Sometimes, Chokidar runs out of file handles, causing `EMFILE` and `ENOSP` errors:
- * `bash: cannot set terminal process group (-1): Inappropriate ioctl for device bash: no job control in this shell`
- * `Error: watch /home/ ENOSPC`
- There are two things that can cause it.
- 1. Exhausted file handles for generic fs operations
- - Can be solved by using [graceful-fs](https://www.npmjs.com/package/graceful-fs),
- which can monkey-patch native `fs` module used by chokidar: `let fs = require('fs'); let grfs = require('graceful-fs'); grfs.gracefulify(fs);`
- - Can also be solved by tuning OS: `echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p`.
- 2. Exhausted file handles for `fs.watch`
- - Can't seem to be solved by graceful-fs or OS tuning
- - It's possible to start using `usePolling: true`, which will switch backend to resource-intensive `fs.watchFile`
- All fsevents-related issues (`WARN optional dep failed`, `fsevents is not a constructor`) are solved by upgrading to v4+.
- ## Changelog
- - **v4 (Sep 2024):** remove glob support and bundled fsevents. Decrease dependency count from 13 to 1. Rewrite in typescript. Bumps minimum node.js requirement to v14+
- - **v3 (Apr 2019):** massive CPU & RAM consumption improvements; reduces deps / package size by a factor of 17x and bumps Node.js requirement to v8.16+.
- - **v2 (Dec 2017):** globs are now posix-style-only. Tons of bugfixes.
- - **v1 (Apr 2015):** glob support, symlink support, tons of bugfixes. Node 0.8+ is supported
- - **v0.1 (Apr 2012):** Initial release, extracted from [Brunch](https://github.com/brunch/brunch/blob/9847a065aea300da99bd0753f90354cde9de1261/src/helpers.coffee#L66)
- ### Upgrading
- If you've used globs before and want do replicate the functionality with v4:
- ```js
- // v3
- chok.watch('**/*.js');
- chok.watch("./directory/**/*");
- // v4
- chok.watch('.', {
- ignored: (path, stats) => stats?.isFile() && !path.endsWith('.js'), // only watch js files
- });
- chok.watch('./directory');
- // other way
- import { glob } from 'node:fs/promises';
- const watcher = watch(await Array.fromAsync(glob('**/*.js')));
- // unwatching
- // v3
- chok.unwatch('**/*.js');
- // v4
- chok.unwatch(await glob('**/*.js'));
- ```
- ## Also
- Why was chokidar named this way? What's the meaning behind it?
- >Chowkidar is a transliteration of a Hindi word meaning 'watchman, gatekeeper', चौकीदार. This ultimately comes from Sanskrit _ चतुष्क_ (crossway, quadrangle, consisting-of-four). This word is also used in other languages like Urdu as (چوکیدار) which is widely used in Pakistan and India.
- ## License
- MIT (c) Paul Miller (<https://paulmillr.com>), see [LICENSE](LICENSE) file.
|