Today I wrote a file watching library that wraps @parcel/watcher
as an alternative to Chokidar.
https://github.com/alloc/filespy/
Features
- Emits files only
- Crawls asynchronously before watching
- Powered by
@parcel/watcher
for native performance, event throttling, and Watchman support - Tolerates permission errors
- Has powerful pattern syntax
- Handles renamed directories properly
- Exposes the paths being watched
- Exposes the paths that were skipped
- Ensures file paths use forward slashes
- Protects against reentrancy by using
setImmediate
before emitting - Splits up long-running listeners with
setImmediate
- Crashes if you don't handle
error
events - Waits for root directory to exist
Usage
import filespy from 'filespy'
const spy = filespy(process.cwd(), {
only: ['*.[jt]sx?'],
skip: ['node_modules'],
}).on('all', (event, file, stats, cwd) => {
// "file" argument is relative to "cwd"
// "stats" is from lstat call
if (event == 'create') {
// File created.
} else if (event == 'update') {
// File changed.
} else {
// File deleted.
}
}).on('error', error => {
// Permission error or watcher failed.
}).on('ready', () => {
// Initial crawl completed. Watcher initialized.
})
spy.dirs // Set of watched directories.
spy.files // Sorted list of watched paths (even directories).
spy.skipped // Sorted list of existing paths that were skipped.
// List all watched paths within a watched directory.
// Returned paths are relative to cwd.
spy.list('foo/bar')
// Stop watching.
spy.close()
Events
interface {
all(
event: 'create' | 'update' | 'delete',
/** Path relative to cwd */
file: string,
/** Equals null for "delete" events */
stats: fs.Stats | null, // https://nodejs.org/api/fs.html#fs_class_fs_stats
/** The root directory */
cwd: string
): void
/** Permission error or watcher failure */
error(error: Error): void
/** Directory was crawled */
crawl(dir: string, cwd: string): void
/** Watcher is ready */
ready(): void
/** File created */
create(file: string, stats: fs.Stats, cwd: string): void
/** File changed */
update(file: string, stats: fs.Stats, cwd: string): void
/** File deleted */
delete(file: string, cwd: string): void
}
Pattern syntax
Filespy mixes globbing with regular expressions, a concept borrowed from Recrawl.
- When a path has no separators (
/
), only the basename is matched.
'*.js' // matches 'a.js' and 'a/b.js'
- Recursivity is implicit.
'a/b' // identical to '**/a/b'
- Use a leading separator to match against the root.
'/*.js' // matches 'a.js' not 'a/b.js'
- Use a trailing separator to match all descendants.
'foo/' // matches 'foo/bar' and 'foo/bar/baz' etc
- Regular expression syntax is supported. (except dot-all)
'*.jsx?' // matches 'a.js' and 'b.jsx'
'*.(js|ts)' // matches 'a.js' and 'b.ts'
- Recursive globbing is supported.
'foo/**/bar' // matches 'foo/bar' and 'foo/a/b/c/bar' etc
Top comments (1)
Now that you understand how to use URL to identify files and folders, close the playground. It's time to build an app! File Spy. witchcraft spells easy