Механизм динамического импорта import() в стандарте
ECMAScript представляет собой выражение, возвращающее Promise, который
резолвит модуль в момент выполнения кода. В отличие от статического
import, который обрабатывается на этапе парсинга и
компиляции, динамический импорт выполняется во время исполнения, что
открывает возможность ленивой загрузки кода и разделения бандла на
отдельные чанки.
В контексте сборщика Rollup поддержка import() является
ключевым элементом системы code splitting и напрямую влияет на то, как
формируются выходные чанки, как организуется граф зависимостей и как
осуществляется загрузка модулей в рантайме.
Выражение import(moduleSpecifier) возвращает
Promise:
import('./module.js').then((module) => {
module.init();
});
Особенности:
Ключевая характеристика — динамичность разрешения модуля, что делает невозможным его статическую фиксацию без анализа выполнения кода.
Rollup рассматривает import() как точку разделения графа
модулей на отдельные чанки. При встрече такого выражения происходит:
import() на загрузчик, соответствующий
формату вывода.Пример:
// entry.js
button.addEventListener('click', async () => {
const module = await import('./heavy-module.js');
module.run();
});
Rollup преобразует это в:
Динамический импорт является триггером code splitting. Rollup строит два уровня графа:
При этом важно:
На формирование чанков влияют:
import();manualChunks;Пример manualChunks:
export default {
input: 'src/main.js',
output: {
format: 'es',
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor';
}
}
}
};
При этом динамические импорты продолжают формировать отдельные чанки поверх ручного разбиения.
Rollup требует, чтобы аргумент import() был
анализируемым:
import('./module.js');
import(`./modules/${name}.js`);
Пример проблемного кода:
import(getPath()); // Rollup не может определить зависимость
Для поддержки шаблонных путей используется механизм анализа переменных импорта:
import(`./pages/${page}.js`);
Rollup не может сам по себе гарантировать полный набор возможных модулей. Для этого используется плагин:
@rollup/plugin-dynamic-import-varsОн выполняет:
Поведение import() зависит от формата output.
import('./module.js')
Остаётся в виде динамического ESM-загрузчика, если окружение поддерживает ESM.
Rollup преобразует:
System.import('./module.js')
или аналогичный runtime-вызов через System loader.
В не-ESM форматах Rollup вынужден эмулировать динамическую загрузку:
Это увеличивает объём runtime-кода.
При использовании import() Rollup генерирует:
Процесс выполнения:
import();Динамический импорт влияет на tree-shaking следующим образом:
Rollup поддерживает цепочки:
button.oncl ick = async () => {
const a = await import('./a.js');
const b = await a.load();
};
Каждый уровень:
Если несколько динамических импортов используют один и тот же модуль:
Типичные проблемы при работе с import():
import(variable);
Решение: использовать статические шаблоны или плагин анализа.
Если модуль CommonJS используется через динамический импорт:
Каждый import():
Rollup позволяет контролировать структуру файлов:
output: {
format: 'es',
chunkFileNames: 'chunks/[name]-[hash].js'
}
Для динамических импортов это критично, поскольку:
При использовании top-level await внутри модулей, загружаемых через
import():
Использование import() в Rollup приводит к архитектурным
изменениям:
Rollup в этом контексте выступает не просто сборщиком, а инструментом формирования runtime-архитектуры модульной системы.