Хук writeBundle и closeBundle

Фаза завершения сборки в Rollup начинается после генерации графа модулей и формирования итоговых бандлов и охватывает набор хуков, отвечающих за запись файлов и постобработку результата. Среди них ключевую роль играют два плагин-хука: writeBundle и closeBundle. Эти хуки относятся к финальной стадии пайплайна и используются для операций, которые должны выполняться после того, как Rollup сформировал выходные файлы.


Позиция хуков в жизненном цикле сборки

Для понимания роли writeBundle и closeBundle важно учитывать общий порядок выполнения ключевых хуков:

  1. buildStart
  2. resolveId / load / transform
  3. moduleParsed
  4. buildEnd
  5. outputOptions
  6. renderStart
  7. augmentChunkHash
  8. generateBundle
  9. writeBundle
  10. closeBundle

writeBundle и closeBundle находятся в самом конце процесса, когда:

  • все чанки уже сформированы;
  • итоговая структура бандла уже известна;
  • файлы (в большинстве случаев) уже записаны на диск.

Хук writeBundle

Назначение

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

Ключевая особенность:

writeBundle вызывается после записи файлов, но до полного завершения процесса сборки.


Сигнатура

writeBundle(outputOptions, bundle)

Параметры

outputOptions Объект с конфигурацией выходного бандла:

  • формат (esm, cjs, iife и т.д.)
  • путь вывода
  • sourcemap настройки
  • прочие параметры output

bundle Объект, содержащий информацию о всех сгенерированных чанках и ассетах:

  • chunks (JS-файлы)
  • assets (CSS, изображения и др.)
  • метаданные каждого файла

Особенности поведения

  • Может быть синхронным или асинхронным (поддерживает async)
  • Вызывается отдельно для каждого output-конфига (если их несколько)
  • Доступен полный итоговый результат сборки
  • Не влияет на уже записанные файлы (это важно: изменения здесь не переписывают бандл автоматически)

Типичные сценарии использования

1. Публикация артефактов

После сборки файлы могут быть отправлены в CDN или облачное хранилище.

export default function uploadPlugin() {
  return {
    name: 'upload-plugin',

    async writeBundle(options, bundle) {
      for (const [fileName, output] of Object.entries(bundle)) {
        if (output.type === 'asset') {
          await uploadToCDN(fileName, output.source);
        }
      }
    }
  };
}

2. Генерация отчётов о сборке

writeBundle удобно использовать для анализа размера бандла.

export default function bundleReport() {
  return {
    name: 'bundle-report',

    writeBundle(options, bundle) {
      const report = Object.entries(bundle).map(([name, item]) => {
        return {
          name,
          type: item.type,
          size: item.type === 'chunk' ? item.code.length : item.source.length
        };
      });

      console.table(report);
    }
  };
}

3. Постобработка ассетов

Например, переименование, логирование, генерация манифестов.

export default function manifestPlugin() {
  return {
    name: 'manifest-plugin',

    writeBundle(options, bundle) {
      const manifest = {};

      for (const file of Object.values(bundle)) {
        if (file.type === 'chunk') {
          manifest[file.fileName] = file.facadeModuleId;
        }
      }

      fs.writeFileSync('dist/manifest.json', JSON.stringify(manifest, null, 2));
    }
  };
}

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

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

Хук closeBundle

Назначение

closeBundle — это финальный хук жизненного цикла сборки Rollup. Он вызывается после завершения всех операций записи и является точкой завершения процесса.

Ключевая особенность:

closeBundle вызывается один раз в конце всей сборки, независимо от количества output-конфигураций.


Сигнатура

closeBundle()

или

async closeBundle() {}

Отличия от writeBundle

Характеристика writeBundle closeBundle
Частота вызова Для каждого output Один раз за сборку
Доступ к bundle Есть Нет
Фаза После записи файлов Финальное завершение
Асинхронность Поддерживается Поддерживается

Основные сценарии использования

1. Очистка временных ресурсов

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

export default function tempPlugin() {
  return {
    name: 'temp-plugin',

    buildStart() {
      this.tempFiles = [];
    },

    generateBundle(_, bundle) {
      // создание временных файлов
    },

    closeBundle() {
      for (const file of this.tempFiles || []) {
        fs.unlinkSync(file);
      }
    }
  };
}

2. Завершение CI/CD процессов

closeBundle используется как финальная точка интеграции с пайплайнами.

export default function ciNotifier() {
  return {
    name: 'ci-notifier',

    async closeBundle() {
      await notifyCI({
        status: 'success',
        timestamp: Date.now()
      });
    }
  };
}

3. Финальное логирование

В отличие от writeBundle, closeBundle подходит для глобальных логов сборки.

export default function finalLogger() {
  return {
    name: 'final-logger',

    closeBundle() {
      console.log('Сборка завершена полностью');
    }
  };
}

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

В режиме rollup --watch:

  • closeBundle вызывается после каждой пересборки
  • writeBundle также вызывается при каждом output
  • важно учитывать возможные утечки ресурсов при повторных вызовах

Ошибки и обработка

Ошибки внутри closeBundle:

  • могут прервать процесс завершения
  • не влияют на уже записанные файлы
  • должны обрабатываться аккуратно через try/catch
closeBundle() {
  try {
    cleanupTemp();
  } catch (e) {
    console.error('Ошибка очистки:', e);
  }
}

Взаимодействие writeBundle и closeBundle

Эти два хука образуют последовательный финальный слой:

  • writeBundle — работа с результатом конкретного output
  • closeBundle — глобальное завершение всей сборки

Типичная цепочка финальных операций:

  1. генерация чанков
  2. запись файлов
  3. writeBundle (по каждому output)
  4. агрегация и финализация
  5. closeBundle (один раз)

Практические рекомендации

Использование writeBundle

Подходит, если требуется:

  • анализ или обработка итогового бандла
  • работа с файлами после записи
  • генерация метаданных (manifest, stats)
  • загрузка артефактов

Использование closeBundle

Подходит, если требуется:

  • финальная очистка ресурсов
  • завершение внешних процессов
  • уведомления CI/CD
  • глобальная синхронизация состояния

Важные нюансы архитектуры

  • writeBundle зависит от output-конфигурации, closeBundle — нет
  • writeBundle предоставляет доступ к структуре бандла, closeBundle — нет
  • writeBundle ближе к данным, closeBundle ближе к завершению процесса
  • closeBundle — последний гарантированный хук выполнения в Rollup

Применение в сложных плагинах

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

  • writeBundle: собрать информацию о файлах
  • closeBundle: использовать эту информацию для финального действия
export default function advancedPlugin() {
  let stats = [];

  return {
    name: 'advanced-plugin',

    writeBundle(options, bundle) {
      stats = Object.keys(bundle);
    },

    closeBundle() {
      fs.writeFileSync('stats.json', JSON.stringify(stats));
      console.log('Статистика записана');
    }
  };
}