0
# Watcher Modes
1
2
Different watcher implementations for various use cases and environments, all providing a consistent EventEmitter-based API with the same event types and method signatures.
3
4
## Capabilities
5
6
### NodeWatcher (Default Mode)
7
8
Uses Node.js built-in `fs.watch` for efficient native file system watching.
9
10
```javascript { .api }
11
/**
12
* Default fs.watch-based watcher
13
* @param {string} dir - Directory to watch
14
* @param {Object} options - Watcher options
15
*/
16
class NodeWatcher extends EventEmitter {
17
constructor(dir, options);
18
19
/**
20
* Stop watching and clean up resources
21
* @param {Function} callback - Optional callback called when closed
22
*/
23
close(callback);
24
}
25
```
26
27
**Best for:**
28
- General use cases on Linux and macOS
29
- Applications requiring low CPU usage and fast response times
30
- When native file system events are available and reliable
31
32
**Limitations:**
33
- May have issues on some network file systems
34
- Windows compatibility varies
35
- Can hit file descriptor limits with many directories
36
37
**Usage Example:**
38
39
```javascript
40
const { NodeWatcher } = require('sane');
41
42
const watcher = new NodeWatcher('/path/to/watch', {
43
glob: ['**/*.js', '**/*.json'],
44
ignored: ['node_modules/**']
45
});
46
47
watcher.on('ready', () => console.log('NodeWatcher ready'));
48
watcher.on('change', (file) => console.log('Changed:', file));
49
```
50
51
### PollWatcher (Polling Mode)
52
53
Uses `fs.watchFile` polling for maximum compatibility across all environments.
54
55
```javascript { .api }
56
/**
57
* Polling-based watcher using fs.watchFile
58
* @param {string} dir - Directory to watch
59
* @param {Object} options - Watcher options including interval
60
*/
61
class PollWatcher extends EventEmitter {
62
constructor(dir, options);
63
64
/**
65
* Stop watching and clean up resources
66
* @param {Function} callback - Optional callback called when closed
67
*/
68
close(callback);
69
}
70
```
71
72
**Additional Options:**
73
74
```javascript { .api }
75
interface PollWatcherOptions {
76
/** Polling interval in milliseconds (default: 100) */
77
interval?: number;
78
}
79
```
80
81
**Best for:**
82
- Network file systems (NFS, CIFS, etc.)
83
- Virtual environments like Vagrant
84
- When native file system events are unreliable
85
- Cross-platform consistency requirements
86
87
**Limitations:**
88
- Higher CPU usage due to constant polling
89
- Slower response time (dependent on polling interval)
90
- May miss very rapid file changes
91
92
**Usage Example:**
93
94
```javascript
95
const { PollWatcher } = require('sane');
96
97
const watcher = new PollWatcher('/path/to/watch', {
98
interval: 1000, // Poll every second
99
glob: ['**/*.css', '**/*.scss']
100
});
101
102
watcher.on('ready', () => console.log('PollWatcher ready'));
103
watcher.on('add', (file) => console.log('Added:', file));
104
```
105
106
### WatchmanWatcher (Watchman Mode)
107
108
Uses Facebook's Watchman for highly efficient watching of large directory trees.
109
110
```javascript { .api }
111
/**
112
* Facebook Watchman-based watcher
113
* @param {string} dir - Directory to watch
114
* @param {Object} options - Watcher options including watchmanPath
115
*/
116
class WatchmanWatcher extends EventEmitter {
117
constructor(dir, options);
118
119
/**
120
* Stop watching and clean up resources
121
* @param {Function} callback - Optional callback called when closed
122
*/
123
close(callback);
124
125
/**
126
* Create Watchman subscription options
127
* @returns {Object} Watchman subscription configuration
128
*/
129
createOptions();
130
131
/**
132
* Handle error events from Watchman
133
* @param {Error} error - Error from Watchman service
134
*/
135
handleErrorEvent(error);
136
137
/**
138
* Handle change events from Watchman
139
* @param {Object} resp - Watchman response object
140
*/
141
handleChangeEvent(resp);
142
}
143
```
144
145
**Additional Options:**
146
147
```javascript { .api }
148
interface WatchmanOptions {
149
/** Custom path to Watchman binary */
150
watchmanPath?: string;
151
}
152
```
153
154
**Best for:**
155
- Very large codebases (thousands of files)
156
- Development environments where Watchman is already installed
157
- Applications requiring maximum performance and reliability
158
- Projects that hit fs.watch file descriptor limits
159
160
**Limitations:**
161
- Requires separate Watchman installation
162
- Additional system dependency
163
- More complex setup process
164
165
**Usage Example:**
166
167
```javascript
168
const { WatchmanWatcher } = require('sane');
169
170
const watcher = new WatchmanWatcher('/large/project', {
171
watchmanPath: '/usr/local/bin/watchman',
172
glob: ['src/**/*.js', 'test/**/*.js']
173
});
174
175
watcher.on('ready', () => console.log('Watchman ready'));
176
watcher.on('all', (type, file) => console.log(type, ':', file));
177
```
178
179
### WatchexecWatcher (Watchexec Mode)
180
181
Uses the external watchexec tool for cross-platform file watching.
182
183
```javascript { .api }
184
/**
185
* Watchexec-based watcher using external watchexec process
186
* @param {string} dir - Directory to watch
187
* @param {Object} options - Watcher options
188
*/
189
class WatchexecWatcher extends EventEmitter {
190
constructor(dir, options);
191
192
/**
193
* Stop watching and clean up resources
194
* @param {Function} callback - Optional callback called when closed
195
*/
196
close(callback);
197
198
/**
199
* Emit filesystem events to the watcher
200
* @param {string} type - Event type ('change', 'add', 'delete')
201
* @param {string} file - File path relative to watched directory
202
* @param {fs.Stats|null} stat - File statistics (null for delete events)
203
*/
204
emitEvent(type, file, stat);
205
}
206
207
/**
208
* Static message handler for processing watchexec output
209
* @static
210
*/
211
WatchexecWatcher._messageHandler;
212
```
213
214
**Best for:**
215
- Cross-platform consistency
216
- When other watchers have platform-specific issues
217
- Integration with existing watchexec workflows
218
219
**Limitations:**
220
- Requires separate watchexec installation
221
- Additional external process overhead
222
- Less mature integration compared to other modes
223
224
**Usage Example:**
225
226
```javascript
227
const { WatchexecWatcher } = require('sane');
228
229
const watcher = new WatchexecWatcher('/path/to/watch', {
230
ignored: ['*.tmp', 'build/**']
231
});
232
233
watcher.on('ready', () => console.log('Watchexec ready'));
234
watcher.on('delete', (file) => console.log('Deleted:', file));
235
```
236
237
## Common Event Interface
238
239
All watcher classes emit the same events with identical signatures:
240
241
```javascript { .api }
242
interface WatcherEvents {
243
/** Emitted when watcher is ready to detect changes */
244
'ready': () => void;
245
246
/** Emitted when a file is modified */
247
'change': (filepath: string, root: string, stat: fs.Stats) => void;
248
249
/** Emitted when a file or directory is added */
250
'add': (filepath: string, root: string, stat: fs.Stats) => void;
251
252
/** Emitted when a file or directory is deleted (stat parameter is null) */
253
'delete': (filepath: string, root: string, stat: null) => void;
254
255
/** Emitted for all change types */
256
'all': (eventType: 'change'|'add'|'delete', filepath: string, root: string, stat?: fs.Stats) => void;
257
258
/** Emitted when errors occur */
259
'error': (error: Error) => void;
260
}
261
```
262
263
## Mode Selection Guidelines
264
265
Choose the appropriate watcher mode based on your environment and requirements:
266
267
1. **NodeWatcher (Default)**: Use for most general applications on modern systems
268
2. **PollWatcher**: Use in virtual environments, network filesystems, or when native events are unreliable
269
3. **WatchmanWatcher**: Use for large projects or when maximum performance is required
270
4. **WatchexecWatcher**: Use when other modes have platform-specific issues
271
272
## Error Handling
273
274
All watchers handle common filesystem errors gracefully:
275
276
- `ENOENT` errors (file not found) are generally ignored
277
- `EPERM` errors on Windows are handled appropriately
278
- Connection errors (Watchman) are propagated as error events
279
- Process spawn errors (Watchexec) are propagated as error events
280
281
```javascript
282
watcher.on('error', (error) => {
283
if (error.code === 'ENOENT') {
284
// File was deleted, usually safe to ignore
285
} else {
286
console.error('Watcher error:', error);
287
}
288
});
289
```