Обработка ошибок и предупреждений через API

Ошибки и предупреждения в Rollup формируют отдельный слой API, через который система сборки сообщает о проблемах разного уровня критичности: от фатальных ошибок компиляции до некритичных, но потенциально опасных предупреждений о неоднозначностях в графе модулей, отсутствии экспортов или неиспользуемом коде. Корректная обработка этих сообщений критична для стабильных CI/CD процессов, автоматических сборок и кастомных плагинов.

Внутри Rollup различаются два основных класса проблем:

Фатальные ошибки (Errors) Прерывают процесс сборки и приводят к выбросу исключения. Обычно возникают при:

  • невозможности разрешить модуль
  • синтаксических ошибках
  • ошибках в плагинах, прерывающих пайплайн
  • некорректной конфигурации input/output

Предупреждения (Warnings) Не останавливают сборку, но сигнализируют о потенциальных проблемах:

  • циклические зависимости
  • неиспользуемые экспортируемые сущности
  • замены имен (name conflicts)
  • динамические импорты с неоднозначным анализом
  • отсутствие разрешения экспортов

Разделение на эти категории является фундаментом API обработки ошибок.

Базовая обработка ошибок через try/catch

При программном использовании Rollup API (rollup.rollup, bundle.generate, bundle.write) фатальные ошибки перехватываются стандартным механизмом исключений:

import { rollup } from 'rollup';

try {
  const bundle = await rollup({
    input: 'src/index.js'
  });

  await bundle.write({
    file: 'dist/bundle.js',
    format: 'esm'
  });

  await bundle.close();
} catch (err) {
  console.error('Ошибка сборки:', err);
}

Объект ошибки обычно имеет расширенную структуру:

  • code — машинный идентификатор типа ошибки
  • message — человекочитаемое описание
  • plugin — имя плагина, если ошибка возникла в нём
  • loc — позиция в коде (если применимо)
  • frame — контекст кода вокруг ошибки
  • stack — стек вызовов

Объект RollupError

Rollup использует расширенный тип ошибок, совместимый с Error, но дополненный полями диагностики:

  • code: string — стабильный идентификатор (например UNRESOLVED_IMPORT)
  • id: string | null — модуль, в котором возникла ошибка
  • pos: number — позиция в файле
  • plugin: string | undefined — источник ошибки
  • watchFiles: string[] — файлы, влияющие на ошибку в watch-режиме

Такая структура позволяет интегрировать Rollup с системами логирования и IDE-подсветкой.

Предупреждения и механизм onwarn

Предупреждения обрабатываются через опцию onwarn, которая принимает функцию-обработчик:

import { rollup } from 'rollup';

const bundle = await rollup({
  input: 'src/index.js',
  onwarn(warning, warn) {
    console.log('WARNING:', warning.code, warning.message);
    warn(warning);
  }
});

Параметр warning имеет структуру:

  • code — тип предупреждения
  • message — текст
  • loc — позиция в исходнике
  • frame — контекст
  • id — файл
  • plugin — источник

Функция warn() — стандартный обработчик Rollup, который выводит предупреждение в консоль или передаёт его дальше в систему логирования.

Фильтрация предупреждений

Одно из распространённых применений onwarn — подавление шумных предупреждений:

onwarn(warning, warn) {
  if (warning.code === 'CIRCULAR_DEPENDENCY') return;
  if (warning.code === 'UNUSED_EXTERNAL_IMPORT') return;

  warn(warning);
}

Такой подход используется в крупных проектах, где часть предупреждений считается допустимой особенностью архитектуры.

Повышение предупреждений до ошибок

В некоторых сборочных пайплайнах предупреждения переводятся в ошибки:

onwarn(warning) {
  throw new Error(`${warning.code}: ${warning.message}`);
}

Это часто применяется в строгих CI-сборках, где требуется нулевой уровень предупреждений.

API plugin.warn и генерация предупреждений

Плагины Rollup могут самостоятельно генерировать предупреждения через this.warn:

export default function myPlugin() {
  return {
    name: 'my-plugin',
    transform(code, id) {
      if (code.includes('eval(')) {
        this.warn({
          code: 'EVAL_USAGE',
          message: 'Использование eval нежелательно',
          id
        });
      }

      return null;
    }
  };
}

Это позволяет плагинам интегрироваться в общий механизм диагностики без прерывания сборки.

Ошибки внутри плагинов

Если плагин выбрасывает исключение, Rollup оборачивает его в структурированную ошибку:

export default function plugin() {
  return {
    name: 'broken-plugin',
    resolveId() {
      throw new Error('resolveId failure');
    }
  };
}

Такие ошибки становятся частью графа сборки и могут содержать plugin и hook:

  • hook — имя жизненного цикла (resolveId, load, transform)
  • plugin — источник

Асинхронные ошибки

Rollup полностью поддерживает async/await в хуках, и ошибки внутри async-кода автоматически прокидываются:

async transform(code) {
  const data = await fetchSomething();

  if (!data) {
    throw new Error('No data');
  }

  return code;
}

Любое исключение превращается в RollupError и передаётся в систему обработки.

Поведение в watch-режиме

При использовании rollup.watch ошибки не останавливают процесс, а передаются через события:

import { watch } from 'rollup';

const watcher = watch({
  input: 'src/index.js',
  output: {
    dir: 'dist',
    format: 'esm'
  }
});

watcher.on('event', event => {
  if (event.code === 'ERROR') {
    console.error('WATCH ERROR:', event.error);
  }
});

Основные события:

  • START — запуск
  • BUNDLE_START — начало сборки
  • BUNDLE_END — завершение
  • ERROR — ошибка
  • END — завершение цикла

Структура event.error

В watch-режиме ошибки дополнительно содержат контекст сборки:

  • watchFiles — список отслеживаемых файлов
  • code — тип ошибки
  • message — текст
  • stack — стек

Это позволяет реализовать устойчивые dev-серверы с горячей перезагрузкой.

Коды предупреждений и стабильность API

Rollup использует стабильные warning.code, которые не зависят от текста сообщения. Это позволяет писать устойчивые фильтры:

  • CIRCULAR_DEPENDENCY
  • THIS_IS_UNDEFINED
  • UNRESOLVED_IMPORT
  • EMPTY_BUNDLE
  • MISSING_EXPORT

Использование кодов вместо строковых сравнений критично для поддержки разных версий Rollup.

Пользовательские стратегии логирования

На практике обработка ошибок часто интегрируется с внешними системами:

onwarn(warning) {
  logger.log({
    level: 'warn',
    code: warning.code,
    message: warning.message,
    module: warning.id
  });
}

Такой подход позволяет централизовать диагностику сборки и связывать её с системой мониторинга.

Прерывание сборки через ошибки плагина

Плагин может явно остановить сборку:

this.error({
  code: 'INVALID_CONFIG',
  message: 'Некорректная конфигурация модуля',
  id
});

this.error всегда прерывает процесс и не может быть проигнорирован через onwarn.

Отличие warn и error в контексте API

  • this.warn — сигнал, не влияющий на поток сборки
  • this.error — немедленное прерывание
  • throw new Error — низкоуровневое исключение, преобразуемое Rollup в структурированную ошибку

Эти механизмы формируют единый слой диагностики.

Влияние ошибок на граф модулей

При ошибках разрешения модулей Rollup частично сохраняет граф, что позволяет:

  • повторно использовать кеш
  • ускорять последующие сборки
  • пересобирать только затронутые узлы

Ошибки становятся частью состояния графа, а не просто выбросом исключения.

Диагностическая информация frame и loc

Rollup старается максимально точно локализовать проблему:

  • loc содержит строку и колонку
  • frame показывает контекст кода с подсветкой строки

Это используется для интеграции с терминалами и IDE.

Кастомизация поведения через onLog (новые версии Rollup)

В современных версиях Rollup вводится расширенная логика логирования через единый канал событий, где warnings и errors могут маршрутизироваться в пользовательские обработчики, объединяя ранее разрозненные механизмы onwarn и plugin logging hooks в единую систему трассировки сборки.