Архитектура Rollup построена вокруг расширяемого пайплайна, в котором почти вся логика сборки делегируется плагинам. Сам бандлер выступает как координатор этапов: разрешение модулей, их загрузка, трансформация, анализ зависимостей, генерация выходного кода и постобработка. Плагины подключаются как набор объектов с заранее определёнными хуками, через которые они «вклиниваются» в процесс сборки.
Ключевая идея системы заключается в том, что каждый этап сборки имеет формализованные точки расширения. Эти точки образуют строгий жизненный цикл, а порядок выполнения плагинов в значительной степени определяет итоговое поведение сборки.
Плагин Rollup — это объект, содержащий набор функций-хуков и метаданных:
name)Минимальный пример:
export default function myPlugin() {
return {
name: 'my-plugin',
resolveId(source) {
return null;
},
load(id) {
return null;
},
transform(code, id) {
return null;
}
};
}
Каждый хук имеет строго определённое место в pipeline и влияет на разные стадии обработки модуля.
Архитектура плагинов делит хуки на несколько категорий:
Эти хуки участвуют в формировании module graph:
optionsbuildStartresolveIdloadtransformmoduleParsedИменно они определяют, какие модули попадут в бандл и как они будут интерпретированы.
Используются при формировании итогового бандла:
renderStartbannerintroaugmentChunkHashrenderChunkgenerateBundlewriteBundlecloseBundleЭти хуки работают уже после построения графа и не влияют на структуру зависимостей.
На этапе инициализации вызывается options. Он позволяет
модифицировать конфигурацию Rollup до начала сборки.
options(inputOptions) {
return inputOptions;
}
Этот хук часто используется для нормализации конфигурации или добавления дефолтных значений.
Далее вызывается buildStart, который сигнализирует о
начале сборки. Он не влияет на граф напрямую, но может инициировать
побочные операции: загрузку данных, кеширование, логирование.
Хук resolveId — один из ключевых элементов архитектуры.
Он отвечает за преобразование строковых импортов в реальные
идентификаторы модулей.
resolveId(source, importer, options) {
if (source === 'virtual-module') {
return source;
}
return null;
}
Если хук возвращает null, Rollup передаёт управление
следующему плагину. Если возвращается строка — это становится финальным
ID модуля.
Особенности архитектуры:
resolveId формирует основу графа зависимостей, поэтому любые ошибки на этом уровне влияют на всю сборку.
После разрешения ID вызывается load. Он отвечает за
получение исходного кода модуля.
load(id) {
if (id === 'virtual-module') {
return 'export const a = 1;';
}
return null;
}
Особенности:
nullЕсли load возвращает null, Rollup читает
файл с диска.
Хук transform — основной механизм изменения кода
модулей.
transform(code, id) {
return {
code: code.replace('var', 'let'),
map: null
};
}
Он вызывается для каждого модуля после загрузки.
Архитектурно transform формирует «слои» обработки, где каждый плагин может модифицировать результат предыдущего.
После трансформации модуль анализируется Rollup’ом (AST-парсинг).
Затем вызывается moduleParsed.
moduleParsed(moduleInfo) {
// доступ к импортам и экспортам
}
Этот хук не изменяет код, но предоставляет доступ к структуре модуля:
Он используется для аналитики и построения дополнительных индексов.
Архитектура Rollup строго определяет порядок:
Такой порядок позволяет комбинировать плагины с предсказуемым поведением.
Каждый хук получает контекст this, содержащий API
Rollup:
this.emitFilethis.resolvethis.getModuleInfothis.addWatchFilethis.cacheКонтекст позволяет плагинам взаимодействовать с системой сборки.
Пример:
transform(code) {
this.addWatchFile('config.json');
return null;
}
Контекст изолирован для каждого плагина, но доступ к общим данным контролируется Rollup.
Архитектура плагинов активно использует концепцию виртуальных модулей. Это модули, которые не существуют на диске, но полностью интегрируются в граф.
Обычно реализуются через связку:
resolveId возвращает виртуальный IDload возвращает кодЭто позволяет:
После построения графа активируются output-хуки.
Позволяет модифицировать отдельные чанки:
renderChunk(code, chunk) {
return code;
}
Используется для:
Работает с финальной структурой бандла:
generateBundle(options, bundle) {
for (const fileName in bundle) {
const chunk = bundle[fileName];
}
}
Позволяет:
Плагины могут влиять на порядок выполнения через:
позицию в массиве plugins
свойство enforce:
prepostвнутренние зависимости между плагинами
Пример:
export default {
name: 'plugin-a',
enforce: 'pre'
}
Архитектурно это создаёт три слоя:
Практически все хуки поддерживают async:
async transform(code) {
const data = await fetchSomething();
return code;
}
Rollup выстраивает внутренний pipeline как цепочку промисов, где каждый этап может ожидать завершения предыдущего.
Это влияет на:
Архитектура плагинов учитывает кеш:
Плагин может управлять кешем через контекст:
Плагины напрямую влияют на tree-shaking:
Особенно важны:
moduleSideEffectsПлагины могут:
Rollup оборачивает выполнение хуков в систему контроля ошибок, связывая их с конкретным модулем.
Плагинная система Rollup намеренно ограничена:
Эти ограничения обеспечивают: