Хук load является одним из ключевых этапов жизненного
цикла плагинов в Rollup и отвечает за загрузку содержимого модуля по его
идентификатору. Этот хук позволяет перехватить процесс чтения исходного
кода файла и либо вернуть собственное содержимое, либо передать
управление следующему плагину в цепочке. На уровне архитектуры Rollup
хук load находится после этапа разрешения идентификатора
модуля (resolveId) и перед этапом трансформации
(transform), формируя связующее звено между поиском модуля
и его обработкой.
Жизненный цикл обработки модуля в Rollup можно представить как последовательность стадий:
resolveId)load)transform)Хук load активируется для каждого модуля, который был
успешно разрешён. Если resolveId определяет путь или
виртуальный идентификатор модуля, именно load отвечает за
получение исходного содержимого этого модуля.
Важно понимать, что Rollup не накладывает ограничений на источник данных: это может быть файл на диске, виртуальный модуль, результат API-запроса или динамически сгенерированный код.
Хук load имеет следующую сигнатуру:
load(id: string) => string | null | void | Promise<string | null | void>
Параметр id представляет собой идентификатор модуля,
полученный на этапе resolveId. Это может быть:
virtual:module)Возвращаемое значение определяет дальнейшее поведение:
string — содержимое модуляnull или undefined — передача управления
следующему плагинуPromise — асинхронная загрузка содержимогоRollup вызывает хук load последовательно по цепочке
плагинов до тех пор, пока один из них не вернёт содержимое модуля. Как
только это происходит, цепочка прерывается, и результат передаётся на
этап transform.
Если ни один плагин не обработал модуль, Rollup использует встроенный механизм чтения файловой системы.
Эта модель делает load инструментом перехвата источника
данных, а не просто чтения файлов.
Порядок выполнения хука load определяется порядком
подключения плагинов:
load для этого модуля не
вызываютсяЭто создаёт предсказуемую модель приоритета, позволяющую переопределять поведение загрузки.
Наиболее распространённый сценарий — создание виртуальных модулей:
export default function virtualModulePlugin() {
return {
name: 'virtual-module',
load(id) {
if (id === 'virtual:example') {
return `export const value = 42;`;
}
return null;
}
};
}
В этом примере модуль virtual:example не существует в
файловой системе, но полностью создаётся на этапе load.
resolveIdХук load почти всегда используется совместно с
resolveId. Их связка позволяет реализовывать виртуальные
модули и псевдонимы:
resolveId определяет идентификаторload возвращает содержимоеТипичный сценарий:
resolveId(source) {
if (source === 'my-virtual') {
return 'virtual:my-virtual';
}
return null;
},
load(id) {
if (id === 'virtual:my-virtual') {
return 'export default "data";';
}
return null;
}
Такая архитектура позволяет полностью абстрагироваться от физического расположения модулей.
Хук load поддерживает асинхронность, что делает его
пригодным для работы с удалёнными ресурсами или файловыми системами:
load(id) {
if (id.startsWith('remote:')) {
return fetch(`https://example.com/modules/${id.slice(7)}`)
.then(res => res.text());
}
return null;
}
Асинхронная модель позволяет интегрировать Rollup с внешними API, базами данных или CDN.
Одной из сильных сторон load является возможность
условной генерации кода:
Пример:
load(id) {
if (id.includes('debug')) {
return `console.log("Debug module loaded"); export default {};`;
}
if (id.endsWith('.special.js')) {
return `export const special = true;`;
}
return null;
}
Виртуальные модули — один из наиболее важных кейсов использования
load. Они позволяют:
Примеры применения:
Rollup может вызывать load несколько раз в рамках разных
сборок или при инвалидации кэша. Поэтому:
id и внешних
стабильных данныхНарушение этих принципов приводит к нестабильной сборке.
Если load выбрасывает исключение, Rollup прерывает
процесс сборки с ошибкой. Это поведение используется для:
Пример:
load(id) {
if (!id.startsWith('/allowed/')) {
throw new Error('Access denied');
}
return fs.readFileSync(id, 'utf-8');
}
Если load возвращает null, Rollup переходит
к стандартному чтению файлов:
fs.readFileidЭто означает, что load полностью опционален для обычных
файловых модулей и нужен только при необходимости переопределения
поведения.
При использовании load важно учитывать влияние на
производительность сборки:
id увеличивают накладные расходыОптимальные практики:
load часто используется совместно с:
resolveId — определение модуляtransform — модификация кодаshouldTransformCachedModule — управление кэшемВ этой связке load выполняет роль источника данных, а не
преобразователя.
Если несколько плагинов реализуют load, они образуют
цепочку:
idnull, вызывается следующийЭто позволяет реализовывать:
На практике часто встречаются следующие проблемы:
undefined вместо строки в сложных
сценарияхidreturn null, из-за чего цепочка
прерываетсяЭти ошибки приводят либо к пропуску модулей, либо к нестабильной сборке.
load формирует фундамент модели модулей Rollup. Он
позволяет:
На уровне архитектуры это один из ключевых механизмов расширяемости Rollup, определяющий, откуда и каким образом поступает исходный код для дальнейшей обработки.