Динамический import() в JavaScript представляет собой
механизм ленивой загрузки модулей, основанный на промисах. В отличие от
статического import, который анализируется на этапе
построения графа зависимостей, динамический импорт выполняется во время
исполнения кода и возвращает Promise, разрешающийся в
модуль.
В контексте Parcel этот механизм становится основой автоматического code splitting, при котором сборщик выделяет отдельные чанки и загружает их только при необходимости.
Динамический импорт использует функцию-подобную конструкцию:
import('./module.js').then((module) => {
module.doSomething();
});
или с async/await:
async function init() {
const module = await import('./module.js');
module.doSomething();
}
На уровне JavaScript это выражение всегда возвращает
Promise, а модуль загружается только при фактическом
выполнении строки.
Parcel интерпретирует такой вызов как сигнал к созданию отдельного
чанка. В результате код ./module.js исключается из
основного бандла и попадает в отдельный файл сборки.
Parcel анализирует AST и определяет выражения вида
import(<specifier>). После этого формируется
отдельный граф зависимостей для каждого динамического импорта.
Каждый динамический импорт приводит к созданию отдельного чанка:
// entry.js
button.addEventListener('click', async () => {
const module = await import('./heavy-module.js');
module.run();
});
Parcel преобразует это в:
heavy-module.[hash].jsЗагрузка этого чанка происходит только при клике на кнопку.
Parcel автоматически добавляет content hash в имя файла:
heavy-module.d3f9a1c8.js
Это обеспечивает:
В режиме разработки Parcel использует dev server с поддержкой HMR
(Hot Module Replacement). Для динамического import() это
означает:
Если модуль поддерживает HMR API, обновление может происходить точечно:
if (module.hot) {
module.hot.accept();
}
Parcel поддерживает статический анализ аргумента
import(). Это важно для корректного разделения кода.
import('./module.js');
import(`./features/${name}.js`);
Во втором случае Parcel пытается определить набор возможных модулей на этапе сборки. Если диапазон слишком широкий, могут быть созданы дополнительные чанки или fallback-логика.
import(variablePath);
Если путь полностью динамический и не может быть разрешён статически, Parcel не способен заранее определить зависимости. Это приводит к ошибке сборки или необходимости ручной настройки через aliasing или явное перечисление модулей.
Динамический импорт влияет на tree shaking иначе, чем статический.
Parcel выполняет tree shaking внутри каждого чанка отдельно. Это означает:
Поле sideEffects в package.json влияет на
оптимизацию:
{
"sideEffects": false
}
Если модуль импортируется динамически, Parcel всё равно учитывает возможные побочные эффекты:
Parcel поддерживает специальные комментарии для управления загрузкой:
import(
/* webpackIgnore: false */
/* parcel-prefetch */
'./module.js'
);
Хотя синтаксис исторически связан с webpack-экосистемой, Parcel интерпретирует часть подсказок для оптимизации поведения загрузки.
Prefetch указывает, что модуль можно загрузить заранее:
Preload применяется, когда модуль точно понадобится в ближайшем будущем:
Parcel может автоматически анализировать контекст и предлагать оптимизацию загрузки без явных директив.
Динамический import() может завершиться ошибкой по
нескольким причинам:
Обработка осуществляется через стандартный механизм промисов:
import('./module.js')
.then((m) => m.run())
.catch((err) => {
console.error('Ошибка загрузки модуля', err);
});
Parcel не подавляет ошибки загрузки и передаёт их в runtime без модификаций.
Parcel транспилирует различные форматы модулей, но динамический import ведёт себя по-разному в зависимости от типа исходного модуля.
export function run() {}
Импорт работает напрямую:
const mod = await import('./esm-module.js');
mod.run();
module.exports = {
run() {}
};
Parcel оборачивает CommonJS-модули в ESM-совместимый слой, поэтому результат import выглядит одинаково:
const mod = await import('./cjs-module.js');
mod.default.run();
Динамический import() в Parcel не является просто
синтаксическим удобством. Он формирует архитектурную модель
приложения:
Пример структуры:
// main entry
router.on('/dashboard', async () => {
const dashboard = await import('./pages/dashboard.js');
dashboard.render();
});
router.on('/settings', async () => {
const settings = await import('./pages/settings.js');
settings.render();
});
Parcel создаёт отдельные чанки для dashboard и
settings, снижая начальный вес приложения.
Parcel использует стратегию content hashing, что влияет на поведение динамических импортов:
Это особенно важно для SPA, где динамические маршруты часто
разделяются через import().
Parcel оптимизирует динамические импорты под современные сетевые протоколы:
Динамический import() в Parcel влияет на:
Ключевой компромисс заключается между:
В монорепозиториях Parcel сохраняет границы модулей между пакетами:
const routes = {
'/home': () => import('./home.js'),
'/profile': () => import('./profile.js')
};
async function loadPlugin(name) {
const plugin = await import(`./plugins/${name}.js`);
return plugin.default;
}
if (user.isAdmin) {
const adminPanel = await import('./admin.js');
adminPanel.init();
}
Parcel строго проверяет динамические выражения import:
Динамический import() в Parcel становится не просто
синтаксической конструкцией языка, а точкой разбиения приложения на
независимые единицы загрузки, определяющей структуру бандла, стратегию
кэширования и модель исполнения кода в браузере.