Интеграция с livereload и dev-серверами

В режиме разработки Rollup функционирует как инкрементальный бандлер, реагирующий на изменения файлов через механизм watch. Основная задача dev-окружения — обеспечить быстрый цикл: изменение кода → пересборка → обновление браузера без ручного перезапуска.

Типовая схема включает три слоя:

  • Rollup watch — отслеживание изменений и пересборка бандла
  • Dev server — раздача файлов и обработка маршрутов
  • LiveReload / автообновление браузера — синхронизация состояния страницы

Rollup сам по себе не является сервером и не управляет браузерной перезагрузкой, поэтому интеграция строится через плагины и внешние HTTP-серверы.


Режим watch и инкрементальная сборка

Механизм watch активируется через CLI или API:

rollup -c -w

или через конфигурацию:

export default {
  input: 'src/main.js',
  output: {
    file: 'dist/bundle.js',
    format: 'esm',
    sourcemap: true
  },
  watch: {
    include: 'src/**',
    clearScreen: false
  }
}

Ключевые особенности:

  • пересборка запускается только при изменённых модулях
  • используется кеш графа модулей
  • сохраняется состояние резолвинга и трансформаций
  • поддерживаются фильтры include и exclude

Watch-режим является базой для всех dev-инструментов, включая live reload и dev server интеграции.


Dev server как слой раздачи

Rollup не предоставляет HTTP-сервера, поэтому применяется rollup-plugin-serve.

Базовая конфигурация:

import serve from 'rollup-plugin-serve';

export default {
  input: 'src/main.js',
  output: {
    file: 'dist/bundle.js',
    format: 'iife',
    sourcemap: true
  },
  plugins: [
    serve({
      open: true,
      port: 3000,
      contentBase: ['dist'],
      verbose: true
    })
  ]
};

Функциональность dev server слоя:

  • статическая раздача файлов
  • поддержка SPA fallback (в некоторых реализациях)
  • логирование запросов
  • автоматическое открытие браузера

Ограничения:

  • отсутствие полноценного middleware pipeline
  • ограниченная поддержка API proxy
  • отсутствие нативного HMR

LiveReload и синхронизация браузера

Для автоматического обновления страницы используется rollup-plugin-livereload.

import livereload from 'rollup-plugin-livereload';

export default {
  input: 'src/main.js',
  output: {
    file: 'dist/bundle.js',
    format: 'iife',
    sourcemap: true
  },
  plugins: [
    serve({
      contentBase: 'dist',
      port: 3000
    }),
    livereload({
      watch: 'dist',
      delay: 200
    })
  ]
};

Механизм работы:

  • плагин отслеживает изменения в указанной директории
  • при изменении файлов запускается WebSocket-сигнал
  • браузер выполняет reload страницы

Варианты поведения:

  • полный reload страницы
  • частичная перезагрузка ресурсов (ограниченно)
  • задержка для сглаживания каскадных сборок

Связка watch + serve + livereload

Типовая архитектура dev-контура строится на взаимодействии трёх компонентов:

  1. Rollup watch пересобирает bundle
  2. Serve раздаёт обновлённые файлы
  3. LiveReload уведомляет браузер

Последовательность событий:

  • изменение src/module.js
  • Rollup пересобирает граф
  • обновляется dist/bundle.js
  • livereload фиксирует изменение в dist
  • отправляется сигнал в браузер
  • страница перезагружается

Критический момент — задержки пересборки. При больших проектах целесообразно настраивать debounce через livereload.delay.


Проблема отсутствия HMR

В классическом Rollup нет полноценного Hot Module Replacement. Это влияет на UX разработки:

  • состояние приложения теряется при reload
  • нет сохранения state компонентов
  • нет точечного обновления модулей

Частично проблема решается сторонними решениями:

  • ручная реализация WebSocket-инвалидации модулей
  • интеграция с React Fast Refresh (через Babel и плагины)
  • использование специализированных плагинов, реализующих ограниченный HMR

Однако архитектурно Rollup ориентирован на build-time оптимизацию, а не runtime патчи модулей.


Альтернативная архитектура dev-сервера

Более гибкий подход — внешний сервер на Node.js (Express/Fastify) с интеграцией Rollup API.

Пример структуры:

  • Express отвечает за HTTP
  • Rollup работает в watch API режиме
  • WebSocket канал сообщает об изменениях
import express from 'express';
import { watch } from 'rollup';

const app = express();
app.use(express.static('dist'));

const watcher = watch({
  input: 'src/main.js',
  output: {
    file: 'dist/bundle.js',
    format: 'esm',
    sourcemap: true
  }
});

watcher.on('event', (event) => {
  if (event.code === 'BUNDLE_END') {
    // отправка сигнала через WebSocket
  }
});

app.listen(3000);

Преимущества такой схемы:

  • полный контроль над middleware
  • возможность API proxy
  • кастомная логика кеширования
  • интеграция с auth и backend логикой

Интеграция с прокси API

Dev-среда часто требует проксирования запросов к backend:

import { createProxyMiddleware } from 'http-proxy-middleware';

app.use('/api', createProxyMiddleware({
  target: 'http://localhost:8080',
  changeOrigin: true
}));

Rollup-плагины напрямую не решают эту задачу, поэтому прокси всегда выносится на уровень сервера.


Оптимизация пересборки и производительности

При использовании watch + livereload важны следующие аспекты:

1. Сокращение области наблюдения

watch: {
  include: 'src/**',
  exclude: 'node_modules/**'
}

2. Разделение конфигураций

  • основной bundle
  • vendor bundle
  • worker bundle

3. Использование кеша Rollup автоматически кеширует граф, но плагины могут нарушать инкрементальность при неправильной реализации transform.

4. Минимизация плагинов в dev режиме Некоторые плагины (minify, terser) замедляют пересборку и должны отключаться.


Sourcemaps в dev-цикле

Sourcemaps являются ключевым элементом интеграции:

output: {
  sourcemap: true
}

Особенности:

  • ускоряют дебаг в браузере
  • увеличивают время сборки при сложных цепочках трансформаций
  • могут конфликтовать с некоторыми пост-обработчиками

При dev-сценариях чаще используется inline sourcemaps, в production — external.


Типовые проблемы интеграции

1. Двойной reload Возникает при одновременном использовании нескольких watch-инстансов или плагинов livereload.

2. Задержка обновления Связана с накоплением нескольких rebuild событий. Решается debounce или throttle.

3. Потеря состояния dev server При пересборке server не обновляет статические ссылки, если кеш браузера не инвалидируется.

4. Конфликты портов Serve и внешние серверы могут конкурировать за один порт.


Паттерны организации dev-конфигурации

Разделение конфигураций:

  • rollup.config.dev.js
  • rollup.config.prod.js

Dev-конфигурация:

  • serve
  • livereload
  • sourcemaps включены
  • минимизация отключена

Production:

  • terser
  • tree-shaking
  • code splitting
  • отключён watch

Интеграция с современными экосистемами

Rollup часто используется как underlying bundler в более высокоуровневых инструментах. В таких системах dev-server слой может быть полностью заменён:

  • собственный dev server фреймворка
  • интеграция через API сборщика
  • WebSocket-driven reload без перезагрузки страницы

При этом Rollup остаётся ответственным исключительно за модульный граф и генерацию бандла, а весь runtime слой выносится наружу.