bundle.generate(): генерация вывода в памяти

Метод bundle.generate() является ключевой частью программного API Rollup и используется для получения итогового бандла без записи файлов на диск. В отличие от bundle.write(), который выполняет физическую запись результатов сборки, bundle.generate() формирует структуру выходных данных полностью в памяти и возвращает её в виде объекта, пригодного для дальнейшей обработки, анализа или передачи в другие системы сборки.

Этот подход используется в случаях, когда требуется интеграция Rollup в собственные инструменты, CI/CD пайплайны, серверные рендереры или любые сценарии, где файловая система либо не используется, либо контролируется отдельно.


Общая сигнатура и поведение

Метод вызывается на экземпляре бандла, полученном через rollup.rollup():

const bundle = await rollup.rollup(inputOptions);

const result = await bundle.generate(outputOptions);

outputOptions в generate() совпадают по структуре с опциями bundle.write(), за исключением того, что любые параметры, связанные с файловой системой, игнорируются.


Структура возвращаемого результата

bundle.generate() возвращает объект следующего вида:

{
  output: OutputChunk[] | OutputAsset[]
}

Где output — массив всех сформированных сущностей бандла:

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

Каждый элемент массива имеет строго определённую структуру.


Типы выходных элементов

Chunk (JavaScript модуль)

Chunk представляет собой итоговый JavaScript-файл или его часть:

{
  type: "chunk",
  fileName: "index.js",
  code: "function test() {}",
  map: {...},
  isEntry: true,
  imports: [],
  dynamicImports: [],
  modules: {...}
}

Ключевые поля:

  • code — итоговый JS-код после всех трансформаций
  • map — sourcemap (если включён)
  • fileName — виртуальное имя файла
  • isEntry — является ли точкой входа
  • imports — зависимости чанка
  • modules — исходные модули, включённые в чанк

Asset (вспомогательный файл)

Asset — это не-JS ресурс:

{
  type: "asset",
  fileName: "style.css",
  source: "body { margin: 0; }"
}

Основные поля:

  • source — содержимое файла (строка или Buffer-like данные)
  • fileName — имя файла
  • type: "asset"

Отличие generate() от write()

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

Метод Результат Файловая система
generate() объект в памяти не используется
write() файлы на диске + объект используется

generate() не выполняет операций ввода-вывода, что делает его более быстрым и предсказуемым в контексте тестирования и серверной обработки.


Использование форматов вывода

Формат определяется через outputOptions.format:

await bundle.generate({
  format: "es"
});

Поддерживаемые форматы:

  • es — ES modules
  • cjs — CommonJS
  • amd — AMD
  • iife — самовызывающийся скрипт
  • umd — универсальный формат

Формат напрямую влияет на структуру code внутри chunk’ов.


Генерация нескольких выходов

Rollup поддерживает мульти-вывод:

const result = await bundle.generate([
  {
    format: "es"
  },
  {
    format: "cjs"
  }
]);

В этом случае возвращается массив результатов:

[
  { output: [...] }, // ES build
  { output: [...] }  // CJS build
]

Каждый набор содержит собственные chunks и assets.


Sourcemap в generate()

Sourcemap генерируется аналогично write(), но остаётся в памяти:

await bundle.generate({
  format: "es",
  sourcemap: true
});

В chunk появится поле:

map: {
  version: 3,
  file: "index.js",
  sources: [...],
  mappings: "..."
}

Sourcemap полезен при:

  • серверной отладке
  • анализе кода без записи на диск
  • интеграции с внешними системами трансформации

Плагины и влияние на generate()

bundle.generate() полностью проходит через pipeline Rollup-плагинов:

  • resolveId
  • load
  • transform
  • renderChunk
  • generateBundle

Финальный этап generateBundle выполняется, но с важной особенностью: отсутствует запись файлов, поэтому любые операции, завязанные на outputOptions.dir или file, не приводят к созданию файловой структуры.


Виртуальные файлы и assets

Плагины могут добавлять новые assets:

generateBundle(options, bundle) {
  bundle["virtual.txt"] = {
    type: "asset",
    fileName: "virtual.txt",
    source: "generated in memory"
  };
}

Эти данные будут присутствовать в результате bundle.generate().


Внутренний механизм формирования результата

Процесс генерации можно условно разбить на этапы:

  1. Анализ модулей
  2. Tree-shaking
  3. Формирование чанков
  4. Применение output plugins
  5. Сериализация кода
  6. Формирование output массива

На этапе 5 Rollup преобразует граф модулей в финальный код, а на этапе 6 упаковывает результат в структуру output.


Пример полного использования

import { rollup } from "rollup";

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

const { output } = await bundle.generate({
  format: "es",
  sourcemap: true
});

for (const chunkOrAsset of output) {
  if (chunkOrAsset.type === "chunk") {
    console.log(chunkOrAsset.code);
  } else {
    console.log(chunkOrAsset.fileName, chunkOrAsset.source);
  }
}

Работа с результатом в памяти

Поскольку результат полностью находится в памяти, его можно:

  • передавать через HTTP API
  • сохранять в базы данных
  • отправлять в облачные storage SDK
  • использовать в тестах без мокирования файловой системы

Ограничения generate()

Несмотря на гибкость, существуют ограничения:

  • отсутствует физическая запись файлов
  • невозможно использовать outputOptions.file как источник побочного эффекта
  • плагины, ожидающие файловой системы, могут работать иначе
  • нет автоматической структуры директорий

Совместимость с bundle.close()

После завершения работы с generate() рекомендуется закрыть бандл:

await bundle.close();

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


Роль generate() в архитектуре Rollup

bundle.generate() занимает промежуточное место между анализом модуля и финальной публикацией результата. Он позволяет отделить:

  • процесс сборки
  • процесс вывода

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