rollup.watch() представляет собой программный интерфейс Rollup,
предназначенный для организации режима наблюдения за изменениями
исходных файлов и автоматической пересборки бандла. В отличие от
CLI-режима --watch, использование API предоставляет полный
контроль над процессом сборки, управлением инстансом watcher, обработкой
событий и интеграцией в собственные инструменты разработки.
При вызове rollup.watch() создаётся объект наблюдателя,
который управляет внутренними сборками Rollup и подписывается на
файловую систему. Внутри используется механизм отслеживания зависимостей
модуля, который строится во время первой сборки графа.
Ключевая особенность архитектуры заключается в том, что watcher не пересоздаёт граф полностью при каждом изменении. Вместо этого он:
Это делает watch-режим существенно быстрее по сравнению с полной
пересборкой через CLI или отдельные вызовы
rollup.rollup().
Функция rollup.watch() принимает конфигурацию или массив
конфигураций и возвращает объект watcher.
import { watch } from 'rollup';
const watcher = watch({
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
}
});
При таком вызове Rollup начинает отслеживание файлов, указанных в графе импорта, начиная с entry-point. Любое изменение триггерит событие пересборки.
Watcher работает как event-driven система. Он генерирует события, отражающие состояние сборки.
Основные события:
START — запуск наблюдения и инициализация графа
модулей;BUNDLE_START — начало очередной сборки;BUNDLE_END — завершение сборки;END — завершение текущего цикла обработки событий;ERROR — ошибка во время сборки или наблюдения.Пример обработки событий:
watcher.on('event', (event) => {
switch (event.code) {
case 'START':
break;
case 'BUNDLE_START':
break;
case 'BUNDLE_END':
break;
case 'ERROR':
console.error(event.error);
break;
}
});
Каждое изменение файла запускает последовательность:
BUNDLE_START и
BUNDLE_END.Важно, что Rollup не всегда пересобирает весь бандл. Если изменение локализовано (например, внутри leaf-модуля), пересборка может быть частичной.
Watcher активно использует механизм кеширования модулей. Каждый модуль хранит:
При изменении файла происходит инвалидация:
Это позволяет избегать повторного парсинга неизменённых частей графа.
Watcher может работать с одним или несколькими output-конфигурациями. В случае массива конфигураций:
watch([
{
input: 'src/a.js',
output: {
file: 'dist/a.js',
format: 'esm'
}
},
{
input: 'src/b.js',
output: {
file: 'dist/b.js',
format: 'cjs'
}
}
]);
Каждая конфигурация создаёт отдельный pipeline сборки, но watcher управляет ими в рамках одного процесса.
Функция rollup.watch() возвращает объект watcher,
который позволяет управлять процессом:
Основной метод управления:
watcher.close();
После вызова close():
Ошибки в watch не останавливают процесс наблюдения. Вместо этого они
передаются через событие ERROR.
watcher.on('event', (event) => {
if (event.code === 'ERROR') {
console.error(event.error);
}
});
Такой подход позволяет продолжать работу даже при наличии синтаксических ошибок или проблем в зависимостях.
Типы ошибок:
При множественных изменениях файлов Rollup использует batching. Это означает, что несколько файловых событий объединяются в одну пересборку.
Механизм работает следующим образом:
Это критически важно при работе с редакторами, которые могут сохранять сразу несколько файлов.
Плагины Rollup активно участвуют в watch-режиме. Каждый из них может:
transform;this.addWatchFile.Пример:
export default function myPlugin() {
return {
transform(code, id) {
this.addWatchFile(id);
return null;
}
};
}
Добавление файлов через addWatchFile расширяет список
наблюдаемых ресурсов, включая не-JS файлы.
Rollup использует нативные file watchers (например,
fs.watch или chokidar в зависимости от
окружения). Поведение может отличаться:
Rollup нормализует эти различия, обеспечивая единое поведение API.
Одной из ключевых оптимизаций является кеширование результатов
transform-плагинов. Если модуль не изменился, его
трансформации повторно не выполняются.
Кеш зависит от:
Это существенно ускоряет пересборку в крупных проектах.
Watch-режим можно рассматривать как реализацию incremental build поверх Rollup. Основные принципы:
В отличие от полного rollup.rollup() вызова, watcher
работает с долгоживущим состоянием.
В реальных проектах последовательность событий может выглядеть так:
Эта модель позволяет интегрировать watcher в системы hot-reload, dev server и CI-инструменты.
Watcher часто применяется как ядро для разработки серверов:
Типичная схема:
const watcher = watch(config);
watcher.on('event', async (event) => {
if (event.code === 'BUNDLE_END') {
const { output } = event;
}
});
Несмотря на гибкость, watch имеет ограничения:
Эти ограничения компенсируются архитектурой incremental rebuild и кешированием, но требуют учёта при проектировании сборочной системы.