@jantimon/glob-watch
Version:
High-performance file watcher with multiple backend options
264 lines (187 loc) • 7.1 kB
Markdown
# /glob-watch
[](https://badge.fury.io/js/%40jantimon%2Fglob-watch)
[](https://opensource.org/licenses/MIT)
A high-performance, flexible file watching utility with smart backend selection
## Features
- **Multiple watching strategies:**
- Uses `fb-watchman` for maximum performance when available
- Falls back to Node.js native `fs.watch` with glob matching
- Supports one-time scanning with `fast-glob`
- **Modern & developer-friendly:**
- TypeScript native (no compilation needed for Node.js 22+, Bun, and Deno)
- Consistent API across all watching backends
- Minimal dependencies
## Motivation
Traditional file watchers often force a trade-off between performance, flexibility, and consistency. With /glob-watch, you get:
- **Optimal performance** by leveraging Facebook's Watchman when available
- **Environment adaptability** with automatic fallbacks for CI environments or platforms like Stackblitz
- **Unified API** regardless of which backend is handling the watching
- **Precise control** over which file information is collected
- **Dual-purpose functionality** with both watching (`watch`) and one-time file discovery (`findFiles`)
## Installation
```bash
npm install /glob-watch
```
Recommended - for optimal watcher performance, consider installing the optional Watchman dependency:
```bash
npm install fb-watchman
```
## Basic Usage
### Watch for Changes
```typescript
import { watch } from "@jantimon/glob-watch";
// Start watching files
const destroy = await watch("src/**/*.ts", (changes) => {
console.log("Added files:", changes.added);
console.log("Changed files:", changes.changed);
console.log("Deleted files:", changes.deleted);
});
// Stop watching when done
destroy();
```
### Find Files (One-time Operation)
```typescript
import { findFiles } from "@jantimon/glob-watch";
// Perfect for build scripts and CI environments
const files = await findFiles("src/**/*.ts");
console.log(`Found ${files.length} TypeScript files`);
```
## API
### watch(patterns, callback, [options])
Starts watching files that match the provided glob pattern(s).
#### Parameters
- `patterns`: `string | string[]` - Glob pattern(s) to match
- `callback`: `(changes: FileChanges) => void | Promise<void>` - Callback function that receives file changes
- `options`: `WatchOptions` (optional) - Configuration options
#### Returns
- `Promise<DestroyFunction>` - A function to stop watching
### findFiles(patterns, [options])
Performs a one-time scan for files matching the provided glob pattern(s).
#### Parameters
- `patterns`: `string | string[]` - Glob pattern(s) to match
- `options`: `WatchOptions` (optional) - Configuration options
#### Returns
- `Promise<string[]>` - Array of matching file paths
### FileChanges
An object containing maps of file changes:
```typescript
interface FileChanges {
added: Map<string, FileInfo>; // New files
changed: Map<string, FileInfo>; // Modified files
deleted: Map<string, FileInfo>; // Removed files
}
```
### FileInfo
Information about a file:
```typescript
interface FileInfo {
// Base fields that will always be available
name: string; // Filename
path: string; // Path to the file (relative or absolute based on options)
// Optional fields that can be requested
exists?: boolean;
type?: string; // File type
size?: number; // File size in bytes
mtime?: number; // Modification time
}
```
## Options
Both `watch` and `findFiles` accept the same options object:
```typescript
{
// Watcher backend selection (for watch function)
mode?: "watchman" | "native" | "fast-glob";
// Which information to include in FileInfo objects
fields?: Array<"type" | "size" | "mtime">;
// Path handling
absolute?: boolean; // Return absolute paths (default: false)
cwd?: string; // Base directory for relative paths (default: process.cwd())
// File filtering
onlyDirectories?: boolean; // Return only directories (default: false)
onlyFiles?: boolean; // Return only files (default: true)
// Pattern matching
dot?: boolean; // Match files starting with . (default: false)
}
```
## Watcher Backends
### watchman (default)
Uses Facebook's [Watchman](https://facebook.github.io/watchman/) through the `fb-watchman` npm package. Offers the best performance and scalability for large projects.
### native
Uses Node.js built-in `fs.watch` API combined with `fast-glob` for initial file discovery and pattern matching. Available everywhere without external Watchman dependency. Used as default fallback for `watch` if `fb-watchman` is not installed.
### fast-glob
Performs a single scan using the `fast-glob` package and immediately returns. Useful for one-time operations when you don't need continuous watching. Used as default fallback for `findFiles` if `fb-watchman` is not installed.
## Examples
### Watch Multiple Patterns
```typescript
const destroy = await watch(["src/**/*.ts", "test/**/*.ts"], (changes) => {
// Handle changes
});
```
### Request Specific File Information
```typescript
const destroy = await watch(
"**/*.js",
(changes) => {
for (const [path, info] of changes.added) {
console.log(
`New file ${path} with size ${info.size} bytes, modified at ${new Date(info.mtime)}`,
);
}
},
{
fields: ["size", "mtime", "type"],
},
);
```
### One-time Scan
There are two ways to perform a one-time scan:
```typescript
// Method 1: Using findFiles
const files = await findFiles("**/*.json");
console.log(`Found ${files.length} JSON files`);
// Method 2: Using watch with fast-glob mode
const destroy = await watch("**/*.json", (changes) => {
// This callback runs once with all matching files in changes.added
console.log(`Found ${changes.added.size} JSON files`);
});
// Stop watching immediately after the initial scan
destroy();
```
### Working with Absolute Paths
```typescript
const destroy = await watch(
"src/**/*.ts",
(changes) => {
// All paths in changes will be absolute
for (const path of changes.added.keys()) {
console.log(`Found: ${path}`);
}
},
{ absolute: true },
);
```
### Focus on Directories Only
```typescript
const destroy = await watch(
"src/**/*",
(changes) => {
// Only directories will be reported
},
{
onlyDirectories: true,
onlyFiles: false,
},
);
```
## Dependencies
- **Required peer dependency:**
- `fast-glob`: For pattern matching in both `native` and `fast-glob` modes
- **Optional dependency:**
- `fb-watchman`: For using the high-performance Watchman backend
If `fb-watchman` isn't available, `/glob-watch` will automatically fallback to `native` mode.
## Compatibility
- **Node.js:** v22.0.0 or higher recommended for TypeScript native support
- **Other runtimes:** Compatible with Bun and Deno
For optimal testing, ensure Watchman is installed on your system.
## License
[MIT](https://opensource.org/licenses/MIT)