Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Динамічний імпорт import()». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**`import()`, це функція, яка завантажує модуль під час виконання програми, а не на етапі завантаження сторінки, і повертає Promise з об'єктом експортів модуля.** Звичайний статичний `import` виконується одразу при старті застосунку, навіть якщо модуль так і не знадобиться, а динамічний завантажує код лише тоді, коли він реально потрібен. Завдяки цьому зменшується розмір основного бандла, пришвидшується перше завантаження сторінки і з'являється можливість підвантажувати код на вимогу. Збирачі (Webpack, Vite, Rollup) бачать `import()` і автоматично виносять такий модуль в окремий чанк, це і є механізм code splitting. Викликати `import()` можна будь-де: усередині функції, обробника події чи умови. ```javascript button.addEventListener('click', async () => { const { showModal } = await import('./modal.js'); showModal(); }); ``` **Ключове:** `import()`, це асинхронне завантаження модуля на вимогу, яке повертає Promise і дає code splitting та ліниве підвантаження.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**`import()`, це функція, яка дозволяє динамічно імпортувати модуль під час виконання (runtime), а не на етапі завантаження сторінки, як звичайний `import`.** Вона повертає Promise, що резолвиться в об'єкт з експортами модуля. ## Теорія ### TL;DR - `import()` завантажує модуль у момент виклику, а не при старті застосунку. - Повертає Promise з об'єктом `{ default, ...namedExports }`. - Зменшує розмір основного бандла і пришвидшує перше завантаження. - Збирачі виносять кожен динамічний імпорт в окремий чанк, це code splitting. - Можна викликати будь-де: у функції, в умові, в обробнику події. - Підтримується в усіх сучасних браузерах і в Node.js від версії 14. ### Швидкий приклад ```javascript // Статичний імпорт, виконується під час завантаження модуля import { add } from './math.js'; // Динамічний імпорт, виконується тоді, коли ми його викличемо const math = await import('./math.js'); console.log(math.add(2, 3)); ``` Звичайний `import`, це статика: він завантажується одразу при старті застосунку, навіть якщо модуль не потрібен. `import()`, це асинхронний виклик: він завантажує модуль лише тоді, коли це справді потрібно. Завдяки цьому зменшується розмір основного бандла (разом з code splitting), пришвидшується початкове завантаження сторінки і з'являється можливість підвантажувати код на вимогу. ### Синтаксис і що повертає import() ```javascript import(modulePath) .then((module) => { // module, це об'єкт з експортами module.default(); // якщо експорт був default module.someFunction(); // якщо іменований експорт }) .catch(console.error); ``` або з `async/await`: ```javascript async function loadMath() { const math = await import('./math.js'); console.log(math.add(2, 3)); } ``` `import()` повертає Promise, який: - виконується успішно і дає об'єкт модуля `{ default, ...namedExports }`; - або завершується помилкою і потрапляє в `catch()`, якщо файл не знайдено або сталася помилка завантаження. ### Ліниве підключення та умовні імпорти ```javascript button.addEventListener('click', async () => { const { showModal } = await import('./modal.js'); showModal(); }); ``` Тут модуль `modal.js` буде завантажено лише при кліку, а не під час початкового завантаження сторінки. Так само працює імпорт за умовою: ```javascript if (user.isAdmin) { const admin = await import('./admin-panel.js'); admin.init(); } ``` Модуль завантажується тільки якщо він потрібен, тобто для адміністраторів. Звичайні користувачі не тягнуть зайвий код. Шлях можна складати з шаблонного рядка: ```javascript const moduleName = 'chart'; const module = await import(`./plugins/${moduleName}.js`); ``` Але важливо: шлях має бути відомий збирачеві заздалегідь, інакше він може не включити файл у збірку. На практиці збирач бере статичну частину шляху (`./plugins/`) і додає в бандл усі файли з цієї теки. ### Як це працює у збирачах У збирачах на кшталт Webpack, Vite чи Rollup виклик `import()` автоматично створює окремий чанк, тобто окремий файл. Наприклад: ```javascript import('./analytics.js'); ``` створить окремий файл `analytics-XYZ.chunk.js`, який завантажиться лише при виклику `import()`. Це і є механізм code splitting, динамічне підвантаження коду. ### Відмінності від звичайного import | Властивість | `import` (статичний) | `import()` (динамічний) | | --- | --- | --- | | Синтаксис | `import { x } from 'y'` | `await import('y')` | | Коли виконується | Під час завантаження модуля | Під час виконання, за викликом | | Асинхронність | Синхронний на рівні збірки | Асинхронний, Promise | | Де пишеться | Вгорі файлу | Будь-де: у функції, в умові | | Застосування | Основний код застосунку | Ліниві модулі, code splitting | ### Приклад у React ```jsx import React, { lazy, Suspense } from 'react'; const Settings = lazy(() => import('./Settings')); export default function App() { return ( <Suspense fallback={<p>Loading...</p>}> <Settings /> </Suspense> ); } ``` Тут React використовує `import()` під капотом. Компонент `Settings` завантажується лише тоді, коли його справді відображають. Підсумок: | Ключова ідея | Значення | | --- | --- | | Що робить | Асинхронно завантажує модуль під час виконання | | Що повертає | Promise, який резолвиться в об'єкт експортів | | Для чого | Ліниве завантаження, code splitting, умовні імпорти | | Переваги | Пришвидшує завантаження, зменшує бандл | | Сумісність | Усі сучасні браузери та Node.js 14+ | ### Типові помилки - **Забувати, що це Promise.** `const m = import('./a.js'); m.add(1, 2)` не спрацює, бо `m`, це Promise, потрібні `await` або `.then()`. - **Брати іменований експорт як default.** Об'єкт модуля містить `default` окремим полем, тому для default-експорту потрібно `(await import('./a.js')).default`. - **Складати шлях повністю динамічно.** `await import(userInput)` збирач проаналізувати не може, потрібна хоча б статична основа шляху. - **Не обробляти помилку завантаження.** Мережа може впасти, і без `catch()` користувач отримає порожній екран замість повідомлення чи повторної спроби. - **Розбивати код надто дрібно.** Десятки мікрочанків дають десятки запитів, і виграш від code splitting з'їдається накладними витратами. - **Лінити те, що потрібне одразу.** Якщо модуль потрібен на першому екрані, динамічний імпорт лише додасть затримку замість того, щоб її прибрати.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.