\n```\n\n```javascript\n// module.js\nexport const greeting = 'Hello';\nexport function sayHi() {\n console.log('Hi!');\n}\n```\n\n**Что происходит:**\n\n1. Браузер видит `import('./module.js')`\n2. Загружает файл `module.js` через HTTP запрос\n3. Парсит его как ES модуль\n4. Возвращает Promise с модулем\n5. Код выполняется асинхронно\n\n#### Пример в браузере\n\n```html\n\n\n\n Dynamic Import\n\n\n \n
\n \n \n\n\n```\n\n```javascript\n// hello.js\nexport const greeting = 'Hello from dynamic import!';\n\nexport function sayHi() {\n console.log('Module loaded dynamically');\n}\n```\n\n**Как это работает в браузере:**\n\n1. Страница загружается, кнопка показывается\n2. `hello.js` НЕ загружается\n3. Клик по кнопке -> вызывается `import('./hello.js')`\n4. Браузер отправляет GET запрос на `hello.js`\n5. Модуль загружается и выполняется\n6. Promise resolve с модулем\n7. Код использует экспорты\n\n### Динамический импорт с Webpack/Vite/Parcel\n\nСборщик вмешивается в процесс.\n\n#### Webpack\n\n```javascript\n// Исходный код\nconst module = await import('./heavy.js');\n\n// После сборки Webpack преобразует в:\nconst module = await __webpack_require__.e(\"src_heavy_js\")\n .then(__webpack_require__.bind(null, \"./src/heavy.js\"));\n```\n\n**Что делает Webpack:**\n\n1. **Code Splitting** — выделяет динамический импорт в отдельный chunk\n2. **Lazy Loading** — создаёт отдельный bundle файл\n3. **Добавляет logic** — код загрузки chunk'а через JSONP или другие методы\n4. **Преобразует Promise** — вместо нативного импорта используется Webpack логика\n\n**На диске:**\n```\ndist/\n├── main.js (основной bundle)\n├── src_heavy_js.bundle.js (отдельный chunk для динамического импорта)\n└── manifest.js (информация о chunks)\n```\n\n**В браузере при загрузке:**\n```\n1. Загружается main.js\n2. При клике на импорт, Webpack загружает src_heavy_js.bundle.js\n3. После загрузки merge'ит модули и execute\n```\n\n#### Vite\n\n```javascript\n// Исходный код\nconst module = await import('./heavy.js');\n\n// Vite оставляет более близким к нативному:\nconst module = await import('./heavy.js?import');\n```\n\nVite использует нативный динамический импорт браузера, только преобразует пути для работы с его модулем-system.\n\n### Проблема: запросы и CORS\n\nДинамический импорт отправляет HTTP запрос. Это имеет следствия:\n\n#### CORS ошибки\n\n```javascript\n// В браузере на https://example.com\nconst module = await import('https://other-domain.com/module.js');\n// CORS error! if other-domain не позволил cross-origin\n```\n\n**Решение:** сервер должен иметь CORS заголовки\n\n```javascript\n// На сервере other-domain.com\nres.setHeader('Access-Control-Allow-Origin', '*');\n```\n\n#### Content-Type\n\n```javascript\n// Ошибка: модуль должен иметь Content-Type: application/javascript\nconst module = await import('/data.json');\n// Failed: expected javascript, got application/json\n```\n\n### Как браузер кеширует динамические импорты\n\nBраузер использует **HTTP кеш** и **модульный кеш**.\n\n```javascript\n// Первый импорт — загружает с сервера\nconst mod1 = await import('./module.js');\n\n// Второй импорт — из браузерного кеша модулей!\nconst mod2 = await import('./module.js');\n\n// mod1 === mod2 (тот же объект модуля)\nconsole.log(mod1 === mod2); // true\n```\n\n**Оптимизация:** браузер запомнил модуль, не загружает второй раз.\n\n### Практический пример: Ленивая загрузка страниц\n\n```javascript\n// app.js (без сборщика, чистый браузер)\nclass Router {\n constructor() {\n this.routes = {};\n }\n \n registerRoute(path, moduleUrl) {\n this.routes[path] = moduleUrl;\n }\n \n async navigate(path) {\n if (!this.routes[path]) {\n console.error('Route not found');\n return;\n }\n \n // Динамически загружаем модуль\n const module = await import(this.routes[path]);\n \n // Инициализируем страницу\n module.init();\n }\n}\n\nconst router = new Router();\nrouter.registerRoute('/home', './pages/home.js');\nrouter.registerRoute('/about', './pages/about.js');\nrouter.registerRoute('/contact', './pages/contact.js');\n\n// При клике на ссылку\ndocument.addEventListener('click', async (e) => {\n if (e.target.tagName === 'A') {\n const path = e.target.getAttribute('href');\n await router.navigate(path);\n }\n});\n```\n\n```javascript\n// pages/home.js\nexport function init() {\n document.body.innerHTML = '

Home Page

';\n}\n\n// pages/about.js\nexport function init() {\n document.body.innerHTML = '

About Page

';\n}\n```\n\n### Проблема: Абсолютные пути\n\nДинамический импорт работает с **относительными путями**.\n\n```javascript\n// Работает: относительный путь\nawait import('./module.js');\nawait import('../sibling.js');\n\n// НЕ работает: абсолютный путь (без сборщика)\nawait import('/module.js'); // Ошибка в браузере\n\n// Решение: использовать относительные пути\nawait import('./components/module.js');\n```\n\n**С Webpack это работает** потому что сборщик преобразует пути:\n\n```javascript\n// Исходный код\nawait import('/module.js');\n\n// После Webpack\nawait import('/dist/module.js'); // переписано\n```\n\n### Обработка ошибок\n\n```javascript\ntry {\n const module = await import('./heavy.js');\n console.log('Module loaded:', module);\n} catch (error) {\n // Модуль не найден, CORS ошибка, синтаксическая ошибка\n console.error('Failed to load module:', error);\n}\n```\n\n**Типичные ошибки:**\n\n```\n1. Failed to fetch dynamically imported module (сетевая ошибка)\n2. Unexpected token (синтаксическая ошибка в модуле)\n3. CORS policy (модуль с другого домена)\n4. Content-Type (неправильный тип)\n```\n\n### Типизация в TypeScript\n\n```typescript\n// Динамический импорт с типами\ninterface Module {\n init: () => void;\n config: { name: string };\n}\n\nconst module: Module = await import('./module.js');\nmodule.init();\nconsole.log(module.config.name);\n```\n\n### Производительность: динамический vs статический импорт\n\n```javascript\n// Статический импорт\nimport { heavyComponent } from './heavy.js';\n// Загружается сразу при загрузке страницы\n\n// Динамический импорт\nconst heavyComponent = await import('./heavy.js');\n// Загружается только когда нужно\n```\n\n**Преимущества динамического:**\n- Начальная загрузка быстрее (не загружаем всё сразу)\n- Экономим трафик (модули, которые не используются, не загружаются)\n- Лучше для мобильных\n\n### Заключение\n\n**Динамический импорт без сборщика:**\n\n1. **В браузере работает нативно** — `import()` преобразуется браузером в загрузку модуля\n2. **Отправляет HTTP запрос** — браузер скачивает файл как ES модуль\n3. **Возвращает Promise** — асинхронная загрузка\n4. **Кешируется** — повторные импорты из кеша модулей\n5. **Требует типа модуля** — `
← Назад к вопросам

Как будет работать динамический импорт после сборки без использования сборщика?

1.8 Middle🔥 171 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как будет работать динамический импорт после сборки без использования сборщика?

Отличный вопрос про динамический импорт и как он работает в разных средах. Разберём подробно.

Что такое динамический импорт

// Статический импорт (загружается сразу)
import { Component } from './Component';

// Динамический импорт (загружается по требованию)
const module = await import('./Component');

Динамический импорт в браузере (без сборщика)

В современных браузерах динамический импорт работает напрямую без сборщика:

<!-- index.html -->
<script type="module">
  // Это работает в браузере БЕЗ Webpack/Vite/Parcel
  const module = await import('./module.js');
  console.log(module);
</script>
// module.js
export const greeting = 'Hello';
export function sayHi() {
  console.log('Hi!');
}

Что происходит:

  1. Браузер видит import('./module.js')
  2. Загружает файл module.js через HTTP запрос
  3. Парсит его как ES модуль
  4. Возвращает Promise с модулем
  5. Код выполняется асинхронно

Пример в браузере

<!DOCTYPE html>
<html>
<head>
  <title>Dynamic Import</title>
</head>
<body>
  <button id="btn">Load Module</button>
  <div id="result"></div>
  
  <script type="module">
    const btn = document.getElementById('btn');
    const result = document.getElementById('result');
    
    btn.addEventListener('click', async () => {
      try {
        // Динамически загружаем модуль
        const module = await import('./hello.js');
        
        // Используем экспорты
        result.textContent = module.greeting;
        module.sayHi();
      } catch (error) {
        result.textContent = 'Ошибка загрузки';
      }
    });
  </script>
</body>
</html>
// hello.js
export const greeting = 'Hello from dynamic import!';

export function sayHi() {
  console.log('Module loaded dynamically');
}

Как это работает в браузере:

  1. Страница загружается, кнопка показывается
  2. hello.js НЕ загружается
  3. Клик по кнопке -> вызывается import('./hello.js')
  4. Браузер отправляет GET запрос на hello.js
  5. Модуль загружается и выполняется
  6. Promise resolve с модулем
  7. Код использует экспорты

Динамический импорт с Webpack/Vite/Parcel

Сборщик вмешивается в процесс.

Webpack

// Исходный код
const module = await import('./heavy.js');

// После сборки Webpack преобразует в:
const module = await __webpack_require__.e("src_heavy_js")
  .then(__webpack_require__.bind(null, "./src/heavy.js"));

Что делает Webpack:

  1. Code Splitting — выделяет динамический импорт в отдельный chunk
  2. Lazy Loading — создаёт отдельный bundle файл
  3. Добавляет logic — код загрузки chunk'а через JSONP или другие методы
  4. Преобразует Promise — вместо нативного импорта используется Webpack логика

На диске:

dist/
├── main.js              (основной bundle)
├── src_heavy_js.bundle.js   (отдельный chunk для динамического импорта)
└── manifest.js          (информация о chunks)

В браузере при загрузке:

1. Загружается main.js
2. При клике на импорт, Webpack загружает src_heavy_js.bundle.js
3. После загрузки merge'ит модули и execute

Vite

// Исходный код
const module = await import('./heavy.js');

// Vite оставляет более близким к нативному:
const module = await import('./heavy.js?import');

Vite использует нативный динамический импорт браузера, только преобразует пути для работы с его модулем-system.

Проблема: запросы и CORS

Динамический импорт отправляет HTTP запрос. Это имеет следствия:

CORS ошибки

// В браузере на https://example.com
const module = await import('https://other-domain.com/module.js');
// CORS error! if other-domain не позволил cross-origin

Решение: сервер должен иметь CORS заголовки

// На сервере other-domain.com
res.setHeader('Access-Control-Allow-Origin', '*');

Content-Type

// Ошибка: модуль должен иметь Content-Type: application/javascript
const module = await import('/data.json');
// Failed: expected javascript, got application/json

Как браузер кеширует динамические импорты

Bраузер использует HTTP кеш и модульный кеш.

// Первый импорт — загружает с сервера
const mod1 = await import('./module.js');

// Второй импорт — из браузерного кеша модулей!
const mod2 = await import('./module.js');

// mod1 === mod2 (тот же объект модуля)
console.log(mod1 === mod2);  // true

Оптимизация: браузер запомнил модуль, не загружает второй раз.

Практический пример: Ленивая загрузка страниц

// app.js (без сборщика, чистый браузер)
class Router {
  constructor() {
    this.routes = {};
  }
  
  registerRoute(path, moduleUrl) {
    this.routes[path] = moduleUrl;
  }
  
  async navigate(path) {
    if (!this.routes[path]) {
      console.error('Route not found');
      return;
    }
    
    // Динамически загружаем модуль
    const module = await import(this.routes[path]);
    
    // Инициализируем страницу
    module.init();
  }
}

const router = new Router();
router.registerRoute('/home', './pages/home.js');
router.registerRoute('/about', './pages/about.js');
router.registerRoute('/contact', './pages/contact.js');

// При клике на ссылку
document.addEventListener('click', async (e) => {
  if (e.target.tagName === 'A') {
    const path = e.target.getAttribute('href');
    await router.navigate(path);
  }
});
// pages/home.js
export function init() {
  document.body.innerHTML = '<h1>Home Page</h1>';
}

// pages/about.js
export function init() {
  document.body.innerHTML = '<h1>About Page</h1>';
}

Проблема: Абсолютные пути

Динамический импорт работает с относительными путями.

// Работает: относительный путь
await import('./module.js');
await import('../sibling.js');

// НЕ работает: абсолютный путь (без сборщика)
await import('/module.js');  // Ошибка в браузере

// Решение: использовать относительные пути
await import('./components/module.js');

С Webpack это работает потому что сборщик преобразует пути:

// Исходный код
await import('/module.js');

// После Webpack
await import('/dist/module.js');  // переписано

Обработка ошибок

try {
  const module = await import('./heavy.js');
  console.log('Module loaded:', module);
} catch (error) {
  // Модуль не найден, CORS ошибка, синтаксическая ошибка
  console.error('Failed to load module:', error);
}

Типичные ошибки:

1. Failed to fetch dynamically imported module (сетевая ошибка)
2. Unexpected token (синтаксическая ошибка в модуле)
3. CORS policy (модуль с другого домена)
4. Content-Type (неправильный тип)

Типизация в TypeScript

// Динамический импорт с типами
interface Module {
  init: () => void;
  config: { name: string };
}

const module: Module = await import('./module.js');
module.init();
console.log(module.config.name);

Производительность: динамический vs статический импорт

// Статический импорт
import { heavyComponent } from './heavy.js';
// Загружается сразу при загрузке страницы

// Динамический импорт
const heavyComponent = await import('./heavy.js');
// Загружается только когда нужно

Преимущества динамического:

  • Начальная загрузка быстрее (не загружаем всё сразу)
  • Экономим трафик (модули, которые не используются, не загружаются)
  • Лучше для мобильных

Заключение

Динамический импорт без сборщика:

  1. В браузере работает нативноimport() преобразуется браузером в загрузку модуля
  2. Отправляет HTTP запрос — браузер скачивает файл как ES модуль
  3. Возвращает Promise — асинхронная загрузка
  4. Кешируется — повторные импорты из кеша модулей
  5. Требует типа модуля<script type="module"> в HTML
  6. CORS ограничения — работает только если разрешены cross-origin
  7. Сборщик оптимизирует — Webpack/Vite делают code splitting и оптимизируют загрузку

Это мощный инструмент для оптимизации загрузки и улучшения производительности приложений.