В системе плагинов Rollup мета-информация выступает дополнительным каналом обмена данными между этапами сборки, позволяя плагинам координировать поведение без прямых зависимостей друг от друга. В отличие от стандартных параметров хуков, мета-данные не входят в публичный API модуля и используются как внутренний механизм расширения контекста сборки.
Основная задача мета-информации заключается в передаче сведений, которые:
Такой подход позволяет строить цепочки плагинов, где каждый участник может как читать, так и дополнять общий контекст выполнения.
В Rollup каждый хук получает ограниченный набор аргументов: имя модуля, его содержимое, идентификаторы зависимостей, карту импорта. Однако этих данных недостаточно для сложных сценариев, например:
Для решения этих задач используется механизм meta,
доступный через объект контекста плагина.
Во время выполнения хуков Rollup предоставляет плагинам объект
контекста, в котором доступен набор служебных методов и свойств. Одним
из ключевых элементов этого контекста является
this.meta.
meta представляет собой произвольное хранилище данных,
связанное с текущим процессом сборки. Его структура не фиксирована на
уровне API и определяется плагинами самостоятельно.
Типично он используется как:
Пример концептуального использования:
export default function pluginA() {
return {
name: 'plugin-a',
buildStart() {
this.meta = this.meta || {};
this.meta.startTime = Date.now();
}
};
}
Rollup выполняет плагины последовательно, но не изолированно. Каждый следующий плагин имеет доступ к тому же контексту сборки. Это означает, что мета-данные становятся общим состоянием, доступным всем участникам цепочки.
Мета-информация в Rollup фактически является shared state:
Такой подход требует дисциплины, поскольку отсутствует строгая типизация и контроль конфликтов ключей.
Порядок влияет на то, какие данные окажутся доступны в конкретный момент:
Если плагин записывает мета-информацию в buildStart, она
будет доступна в transform, но недоступна до момента
инициализации сборки.
Для предотвращения конфликтов ключей мета-данные обычно структурируются по пространствам имен:
this.meta = {
myPlugin: {
cache: new Map(),
flags: {
optimized: false
}
}
};
Такой подход снижает риск перезаписи данных другим плагином.
Один из частых сценариев — кэширование результатов тяжелых операций:
export default function pluginCache() {
return {
name: 'plugin-cache',
transform(code, id) {
this.meta = this.meta || {};
this.meta.cache = this.meta.cache || new Map();
if (this.meta.cache.has(id)) {
return this.meta.cache.get(id);
}
const result = code.replace(/console\.log/g, '');
this.meta.cache.set(id, result);
return result;
}
};
}
Здесь meta используется как разделяемый кэш, который может быть доступен другим плагинам.
Мета-информация часто применяется для передачи сигналов между фазами жизненного цикла сборки.
Плагин может устанавливать глобальные флаги:
buildStart() {
this.meta ||= {};
this.meta.hasPolyfills = true;
}
Другой плагин в фазе transform может использовать этот
флаг:
transform(code) {
if (this.meta?.hasPolyfills) {
return code + '\n// polyfills enabled';
}
return code;
}
Таким образом реализуется условная логика без жесткой связности плагинов.
Некоторые плагины собирают статистику:
transform(code, id) {
this.meta ||= {};
this.meta.stats ||= {
files: 0,
totalSize: 0
};
this.meta.stats.files += 1;
this.meta.stats.totalSize += code.length;
return code;
}
В конце сборки другой хук может использовать эти данные:
generateBundle() {
const stats = this.meta.stats;
console.log(stats);
}
Главная проблема заключается в том, что meta является общим состоянием. Это приводит к рискам:
Хотя Rollup определяет порядок хуков, порядок плагинов может быть изменен конфигурацией. Это влияет на содержимое meta в любой момент времени.
Если meta содержит ссылки на большие структуры данных (AST, карты модулей), это может привести к увеличению потребления памяти.
Часто meta инициализируется только при необходимости:
function getMeta(ctx) {
ctx.meta ||= {};
return ctx.meta;
}
Это позволяет унифицировать доступ к данным и уменьшить дублирование кода.
Meta используется как координационный слой между плагинами оптимизации:
Пример координации:
// analyzer
transform(code) {
this.meta.analysis ||= {};
this.meta.analysis.hasDynamicImports = code.includes('import(');
return code;
}
// optimizer
transform(code) {
if (this.meta.analysis?.hasDynamicImports) {
return optimizeAsync(code);
}
return optimizeSync(code);
}
В сложных сборках meta используется для передачи структур AST между плагинами, чтобы избежать повторного парсинга:
parse(code) {
this.meta ||= {};
this.meta.ast = parseCode(code);
}
Дальнейшие плагины могут использовать уже готовое дерево.
При использовании meta в Rollup важно учитывать несколько принципов:
Особенно критично избегать накопления данных между сборками в watch-режиме, так как это приводит к постепенному росту памяти.
В режиме наблюдения за файлами meta может сохраняться между перезапусками сборки. Это позволяет реализовать:
Однако это также создает риск устаревших данных, если плагин не сбрасывает состояние корректно:
buildStart() {
this.meta = {};
}
Meta не является официально стандартизированным API уровня Rollup
как, например, this.emitFile или this.resolve.
Это делает его более гибким, но менее предсказуемым.
В отличие от строго определенных методов контекста:
meta не имеет семантической привязки и может использоваться произвольно, что требует строгой внутренней дисциплины при проектировании плагинов.
В крупных проектах meta становится основой для построения внутренних пайплайнов внутри Rollup:
Каждый этап записывает промежуточные результаты в meta, формируя единый конвейер обработки.
Такой подход позволяет реализовать сложные трансформации без модификации ядра Rollup и без введения дополнительных внешних систем координации.