Next-generation ES module bundler that compiles small pieces of code into larger, more complex applications or libraries
—
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.
Main watch function that creates a file watcher for automatic rebuilding during development.
/**
* Creates a file watcher for automatic rebuilding
* @param configs - Watch configuration(s)
* @returns RollupWatcher event emitter
*/
function watch(configs: RollupWatchOptions | RollupWatchOptions[]): RollupWatcher;
interface RollupWatchOptions extends InputOptions {
/** Output configuration */
output?: OutputOptions | OutputOptions[];
/** Watch-specific options */
watch?: WatcherOptions | false;
}Usage Examples:
import { watch } from "rollup";
// Basic watch setup
const watcher = watch({
input: "src/main.js",
output: {
file: "dist/bundle.js",
format: "esm"
}
});
// Watch with specific options
const watcher = watch({
input: "src/main.js",
output: {
file: "dist/bundle.js",
format: "esm"
},
watch: {
exclude: "node_modules/**",
clearScreen: false
}
});
// Multiple configurations
const watcher = watch([
{
input: "src/main.js",
output: { file: "dist/esm.js", format: "esm" }
},
{
input: "src/main.js",
output: { file: "dist/cjs.js", format: "cjs" }
}
]);Event emitter interface for handling watch events and controlling the watcher lifecycle.
/**
* Watcher instance for rebuild-on-change functionality
*/
interface RollupWatcher extends AwaitingEventEmitter<{
change: (id: string, change: { event: ChangeEvent }) => void;
close: () => void;
event: (event: RollupWatcherEvent) => void;
restart: () => void;
}> {
/** Close the watcher and stop watching */
close(): Promise<void>;
/** Emit an event to all listeners */
emit<K extends keyof T>(event: K, ...parameters: Parameters<T[K]>): Promise<unknown>;
/** Register an event listener */
on<K extends keyof T>(event: K, listener: AwaitedEventListener<T, K>): this;
/** Register a one-time event listener */
onCurrentRun<K extends keyof T>(event: K, listener: AwaitedEventListener<T, K>): this;
/** Remove an event listener */
off<K extends keyof T>(event: K, listener: AwaitedEventListener<T, K>): this;
/** Remove all listeners */
removeAllListeners(): this;
/** Remove listeners for current run only */
removeListenersForCurrentRun(): this;
}
type ChangeEvent = 'create' | 'update' | 'delete';
type AwaitedEventListener<T extends Record<string, (...args: any) => any>, K extends keyof T> =
(...parameters: Parameters<T[K]>) => void | Promise<void>;Comprehensive event handling for monitoring build progress and responding to file changes.
/**
* Event types emitted by the watcher
*/
type RollupWatcherEvent =
| { code: 'START' }
| {
code: 'BUNDLE_START';
input?: InputOption;
output: readonly string[];
}
| {
code: 'BUNDLE_END';
duration: number;
input?: InputOption;
output: readonly string[];
result: RollupBuild;
}
| { code: 'END' }
| {
code: 'ERROR';
error: RollupError;
result: RollupBuild | null;
};Usage Examples:
import { watch } from "rollup";
const watcher = watch(config);
// Handle build events
watcher.on('event', (event) => {
switch (event.code) {
case 'START':
console.log('Starting build...');
break;
case 'BUNDLE_START':
console.log(`Building ${event.input}...`);
break;
case 'BUNDLE_END':
console.log(`Built in ${event.duration}ms`);
break;
case 'END':
console.log('Build complete');
break;
case 'ERROR':
console.error('Build error:', event.error);
break;
}
});
// Handle file changes
watcher.on('change', (id, { event }) => {
console.log(`File ${event}: ${id}`);
});
// Graceful shutdown
process.on('SIGINT', async () => {
await watcher.close();
process.exit(0);
});Methods for controlling watcher behavior and lifecycle.
/**
* Close the watcher and stop watching files
* @returns Promise that resolves when watcher is closed
*/
close(): Promise<void>;
/**
* Restart the watcher with current configuration
*/
restart(): void;Usage Examples:
// Programmatic control
const watcher = watch(config);
// Restart on command
process.on('SIGUSR2', () => {
console.log('Restarting watcher...');
watcher.restart();
});
// Close watcher
setTimeout(async () => {
console.log('Closing watcher...');
await watcher.close();
}, 30000);Detailed configuration options for controlling watch behavior.
interface WatcherOptions {
/** Allow input files inside output directory */
allowInputInsideOutputPath?: boolean;
/** Debounce delay for rebuilds (ms) */
buildDelay?: number;
/** Chokidar file watcher options */
chokidar?: ChokidarOptions;
/** Clear screen on each rebuild */
clearScreen?: boolean;
/** Files/patterns to exclude from watching */
exclude?: string | RegExp | (string | RegExp)[];
/** Files/patterns to include in watching */
include?: string | RegExp | (string | RegExp)[];
/** Skip writing files (generate only) */
skipWrite?: boolean;
/** Callback when files are invalidated */
onInvalidate?: (id: string) => void;
}Advanced file watching options via Chokidar integration.
interface ChokidarOptions {
/** Files/paths to ignore */
ignored?: any;
/** Don't emit events for initially added files */
ignoreInitial?: boolean;
/** Follow symbolic links */
followSymlinks?: boolean;
/** Base directory for relative paths */
cwd?: string;
/** Disable globbing */
disableGlobbing?: boolean;
/** Use polling instead of native events */
usePolling?: boolean;
/** Polling interval (ms) */
interval?: number;
/** Binary file polling interval (ms) */
binaryInterval?: number;
/** Always stat files */
alwaysStat?: boolean;
/** Maximum depth for recursive watching */
depth?: number;
/** Wait for write completion */
awaitWriteFinish?: boolean | {
/** Stability threshold (ms) */
stabilityThreshold?: number;
/** Poll interval (ms) */
pollInterval?: number;
};
/** Ignore permission errors */
ignorePermissionErrors?: boolean;
/** Atomic file moves */
atomic?: boolean | number;
/** Keep process alive */
persistent?: boolean;
/** Use fsevents on macOS */
useFsEvents?: boolean;
}import { watch } from "rollup";
import express from "express";
const app = express();
const watcher = watch({
input: "src/main.js",
output: {
file: "dist/bundle.js",
format: "esm"
},
watch: {
clearScreen: false,
exclude: ["node_modules/**", "dist/**"]
}
});
// Serve files
app.use(express.static("dist"));
// Handle build events
watcher.on('event', (event) => {
if (event.code === 'BUNDLE_END') {
console.log('✓ Build complete, files updated');
} else if (event.code === 'ERROR') {
console.error('✗ Build error:', event.error.message);
}
});
app.listen(3000, () => {
console.log('Dev server running on http://localhost:3000');
});import { watch } from "rollup";
const watcher = watch({
input: "src/main.js",
output: {
file: "dist/bundle.js",
format: "esm"
},
watch: {
buildDelay: 1000, // Wait 1s before rebuilding
exclude: [
"node_modules/**",
"**/*.test.js",
"docs/**"
]
}
});
// Custom file change handling
watcher.on('change', (id, { event }) => {
if (id.includes('.test.')) {
console.log('Test file changed, skipping rebuild');
return;
}
if (event === 'delete') {
console.log(`File deleted: ${id}`);
} else {
console.log(`File ${event}: ${id}`);
}
});
// Error recovery
watcher.on('event', (event) => {
if (event.code === 'ERROR') {
console.error('Build failed:', event.error.message);
console.log('Waiting for file changes to retry...');
}
});import { watch } from "rollup";
// Watch multiple build targets
const watcher = watch([
// Main application
{
input: "src/main.js",
output: {
file: "dist/app.js",
format: "esm"
},
watch: {
include: "src/**"
}
},
// Service worker
{
input: "src/sw.js",
output: {
file: "dist/sw.js",
format: "iife"
},
watch: {
include: "src/sw/**"
}
},
// Styles (with different plugin)
{
input: "src/styles/main.css",
output: {
file: "dist/styles.css",
format: "es"
},
plugins: [postcss()],
watch: {
include: "src/styles/**"
}
}
]);
// Track which configs are building
const buildingConfigs = new Set();
watcher.on('event', (event) => {
switch (event.code) {
case 'BUNDLE_START':
const input = Array.isArray(event.input) ? event.input[0] : event.input;
buildingConfigs.add(input);
console.log(`Building ${input}... (${buildingConfigs.size} active)`);
break;
case 'BUNDLE_END':
const builtInput = Array.isArray(event.input) ? event.input[0] : event.input;
buildingConfigs.delete(builtInput);
console.log(`✓ Built ${builtInput} in ${event.duration}ms`);
break;
}
});Install with Tessl CLI
npx tessl i tessl/npm-rollup