0
# Watch Mode
1
2
Development-focused file watching system that automatically rebuilds when source files change, with comprehensive event handling and error recovery. Rollup's watch mode provides efficient incremental builds and detailed progress reporting.
3
4
## Capabilities
5
6
### Watch Function
7
8
Main watch function that creates a file watcher for automatic rebuilding during development.
9
10
```typescript { .api }
11
/**
12
* Creates a file watcher for automatic rebuilding
13
* @param configs - Watch configuration(s)
14
* @returns RollupWatcher event emitter
15
*/
16
function watch(configs: RollupWatchOptions | RollupWatchOptions[]): RollupWatcher;
17
18
interface RollupWatchOptions extends InputOptions {
19
/** Output configuration */
20
output?: OutputOptions | OutputOptions[];
21
/** Watch-specific options */
22
watch?: WatcherOptions | false;
23
}
24
```
25
26
**Usage Examples:**
27
28
```typescript
29
import { watch } from "rollup";
30
31
// Basic watch setup
32
const watcher = watch({
33
input: "src/main.js",
34
output: {
35
file: "dist/bundle.js",
36
format: "esm"
37
}
38
});
39
40
// Watch with specific options
41
const watcher = watch({
42
input: "src/main.js",
43
output: {
44
file: "dist/bundle.js",
45
format: "esm"
46
},
47
watch: {
48
exclude: "node_modules/**",
49
clearScreen: false
50
}
51
});
52
53
// Multiple configurations
54
const watcher = watch([
55
{
56
input: "src/main.js",
57
output: { file: "dist/esm.js", format: "esm" }
58
},
59
{
60
input: "src/main.js",
61
output: { file: "dist/cjs.js", format: "cjs" }
62
}
63
]);
64
```
65
66
### RollupWatcher Interface
67
68
Event emitter interface for handling watch events and controlling the watcher lifecycle.
69
70
```typescript { .api }
71
/**
72
* Watcher instance for rebuild-on-change functionality
73
*/
74
interface RollupWatcher extends AwaitingEventEmitter<{
75
change: (id: string, change: { event: ChangeEvent }) => void;
76
close: () => void;
77
event: (event: RollupWatcherEvent) => void;
78
restart: () => void;
79
}> {
80
/** Close the watcher and stop watching */
81
close(): Promise<void>;
82
/** Emit an event to all listeners */
83
emit<K extends keyof T>(event: K, ...parameters: Parameters<T[K]>): Promise<unknown>;
84
/** Register an event listener */
85
on<K extends keyof T>(event: K, listener: AwaitedEventListener<T, K>): this;
86
/** Register a one-time event listener */
87
onCurrentRun<K extends keyof T>(event: K, listener: AwaitedEventListener<T, K>): this;
88
/** Remove an event listener */
89
off<K extends keyof T>(event: K, listener: AwaitedEventListener<T, K>): this;
90
/** Remove all listeners */
91
removeAllListeners(): this;
92
/** Remove listeners for current run only */
93
removeListenersForCurrentRun(): this;
94
}
95
96
type ChangeEvent = 'create' | 'update' | 'delete';
97
type AwaitedEventListener<T extends Record<string, (...args: any) => any>, K extends keyof T> =
98
(...parameters: Parameters<T[K]>) => void | Promise<void>;
99
```
100
101
### Event Handling
102
103
Comprehensive event handling for monitoring build progress and responding to file changes.
104
105
```typescript { .api }
106
/**
107
* Event types emitted by the watcher
108
*/
109
type RollupWatcherEvent =
110
| { code: 'START' }
111
| {
112
code: 'BUNDLE_START';
113
input?: InputOption;
114
output: readonly string[];
115
}
116
| {
117
code: 'BUNDLE_END';
118
duration: number;
119
input?: InputOption;
120
output: readonly string[];
121
result: RollupBuild;
122
}
123
| { code: 'END' }
124
| {
125
code: 'ERROR';
126
error: RollupError;
127
result: RollupBuild | null;
128
};
129
```
130
131
**Usage Examples:**
132
133
```typescript
134
import { watch } from "rollup";
135
136
const watcher = watch(config);
137
138
// Handle build events
139
watcher.on('event', (event) => {
140
switch (event.code) {
141
case 'START':
142
console.log('Starting build...');
143
break;
144
case 'BUNDLE_START':
145
console.log(`Building ${event.input}...`);
146
break;
147
case 'BUNDLE_END':
148
console.log(`Built in ${event.duration}ms`);
149
break;
150
case 'END':
151
console.log('Build complete');
152
break;
153
case 'ERROR':
154
console.error('Build error:', event.error);
155
break;
156
}
157
});
158
159
// Handle file changes
160
watcher.on('change', (id, { event }) => {
161
console.log(`File ${event}: ${id}`);
162
});
163
164
// Graceful shutdown
165
process.on('SIGINT', async () => {
166
await watcher.close();
167
process.exit(0);
168
});
169
```
170
171
### Watcher Control
172
173
Methods for controlling watcher behavior and lifecycle.
174
175
```typescript { .api }
176
/**
177
* Close the watcher and stop watching files
178
* @returns Promise that resolves when watcher is closed
179
*/
180
close(): Promise<void>;
181
182
/**
183
* Restart the watcher with current configuration
184
*/
185
restart(): void;
186
```
187
188
**Usage Examples:**
189
190
```typescript
191
// Programmatic control
192
const watcher = watch(config);
193
194
// Restart on command
195
process.on('SIGUSR2', () => {
196
console.log('Restarting watcher...');
197
watcher.restart();
198
});
199
200
// Close watcher
201
setTimeout(async () => {
202
console.log('Closing watcher...');
203
await watcher.close();
204
}, 30000);
205
```
206
207
## Watch Configuration
208
209
### WatcherOptions
210
211
Detailed configuration options for controlling watch behavior.
212
213
```typescript { .api }
214
interface WatcherOptions {
215
/** Allow input files inside output directory */
216
allowInputInsideOutputPath?: boolean;
217
/** Debounce delay for rebuilds (ms) */
218
buildDelay?: number;
219
/** Chokidar file watcher options */
220
chokidar?: ChokidarOptions;
221
/** Clear screen on each rebuild */
222
clearScreen?: boolean;
223
/** Files/patterns to exclude from watching */
224
exclude?: string | RegExp | (string | RegExp)[];
225
/** Files/patterns to include in watching */
226
include?: string | RegExp | (string | RegExp)[];
227
/** Skip writing files (generate only) */
228
skipWrite?: boolean;
229
/** Callback when files are invalidated */
230
onInvalidate?: (id: string) => void;
231
}
232
```
233
234
### Chokidar Integration
235
236
Advanced file watching options via Chokidar integration.
237
238
```typescript { .api }
239
interface ChokidarOptions {
240
/** Files/paths to ignore */
241
ignored?: any;
242
/** Don't emit events for initially added files */
243
ignoreInitial?: boolean;
244
/** Follow symbolic links */
245
followSymlinks?: boolean;
246
/** Base directory for relative paths */
247
cwd?: string;
248
/** Disable globbing */
249
disableGlobbing?: boolean;
250
/** Use polling instead of native events */
251
usePolling?: boolean;
252
/** Polling interval (ms) */
253
interval?: number;
254
/** Binary file polling interval (ms) */
255
binaryInterval?: number;
256
/** Always stat files */
257
alwaysStat?: boolean;
258
/** Maximum depth for recursive watching */
259
depth?: number;
260
/** Wait for write completion */
261
awaitWriteFinish?: boolean | {
262
/** Stability threshold (ms) */
263
stabilityThreshold?: number;
264
/** Poll interval (ms) */
265
pollInterval?: number;
266
};
267
/** Ignore permission errors */
268
ignorePermissionErrors?: boolean;
269
/** Atomic file moves */
270
atomic?: boolean | number;
271
/** Keep process alive */
272
persistent?: boolean;
273
/** Use fsevents on macOS */
274
useFsEvents?: boolean;
275
}
276
```
277
278
## Advanced Watch Patterns
279
280
### Development Server Integration
281
282
```typescript
283
import { watch } from "rollup";
284
import express from "express";
285
286
const app = express();
287
const watcher = watch({
288
input: "src/main.js",
289
output: {
290
file: "dist/bundle.js",
291
format: "esm"
292
},
293
watch: {
294
clearScreen: false,
295
exclude: ["node_modules/**", "dist/**"]
296
}
297
});
298
299
// Serve files
300
app.use(express.static("dist"));
301
302
// Handle build events
303
watcher.on('event', (event) => {
304
if (event.code === 'BUNDLE_END') {
305
console.log('✓ Build complete, files updated');
306
} else if (event.code === 'ERROR') {
307
console.error('✗ Build error:', event.error.message);
308
}
309
});
310
311
app.listen(3000, () => {
312
console.log('Dev server running on http://localhost:3000');
313
});
314
```
315
316
### Conditional Rebuilding
317
318
```typescript
319
import { watch } from "rollup";
320
321
const watcher = watch({
322
input: "src/main.js",
323
output: {
324
file: "dist/bundle.js",
325
format: "esm"
326
},
327
watch: {
328
buildDelay: 1000, // Wait 1s before rebuilding
329
exclude: [
330
"node_modules/**",
331
"**/*.test.js",
332
"docs/**"
333
]
334
}
335
});
336
337
// Custom file change handling
338
watcher.on('change', (id, { event }) => {
339
if (id.includes('.test.')) {
340
console.log('Test file changed, skipping rebuild');
341
return;
342
}
343
344
if (event === 'delete') {
345
console.log(`File deleted: ${id}`);
346
} else {
347
console.log(`File ${event}: ${id}`);
348
}
349
});
350
351
// Error recovery
352
watcher.on('event', (event) => {
353
if (event.code === 'ERROR') {
354
console.error('Build failed:', event.error.message);
355
console.log('Waiting for file changes to retry...');
356
}
357
});
358
```
359
360
### Multi-Config Watch
361
362
```typescript
363
import { watch } from "rollup";
364
365
// Watch multiple build targets
366
const watcher = watch([
367
// Main application
368
{
369
input: "src/main.js",
370
output: {
371
file: "dist/app.js",
372
format: "esm"
373
},
374
watch: {
375
include: "src/**"
376
}
377
},
378
// Service worker
379
{
380
input: "src/sw.js",
381
output: {
382
file: "dist/sw.js",
383
format: "iife"
384
},
385
watch: {
386
include: "src/sw/**"
387
}
388
},
389
// Styles (with different plugin)
390
{
391
input: "src/styles/main.css",
392
output: {
393
file: "dist/styles.css",
394
format: "es"
395
},
396
plugins: [postcss()],
397
watch: {
398
include: "src/styles/**"
399
}
400
}
401
]);
402
403
// Track which configs are building
404
const buildingConfigs = new Set();
405
406
watcher.on('event', (event) => {
407
switch (event.code) {
408
case 'BUNDLE_START':
409
const input = Array.isArray(event.input) ? event.input[0] : event.input;
410
buildingConfigs.add(input);
411
console.log(`Building ${input}... (${buildingConfigs.size} active)`);
412
break;
413
414
case 'BUNDLE_END':
415
const builtInput = Array.isArray(event.input) ? event.input[0] : event.input;
416
buildingConfigs.delete(builtInput);
417
console.log(`✓ Built ${builtInput} in ${event.duration}ms`);
418
break;
419
}
420
});
421
```