Фундамент Ф1 · урок 9 з 12
Модулі: import і export
Кожен файл Angular-проєкту починається з рядків import { … } from '…'. Модулі — це
спосіб, яким файли діляться кодом: що один файл віддає назовні й що інший бере собі. Урок короткий, але після нього
шапки файлів перестануть бути магією, а рядок про lazy loading з роутингу нарешті стане зрозумілим.
Навіщо модулі
Колись увесь JavaScript сторінки жив в одному спільному просторі: змінна total з одного скрипта
затирала total з іншого. Модулі розвʼязали це просто: кожен файл — окрема область видимості.
Усе, що в ньому оголошено, за замовчуванням видно лише всередині. Назовні йде тільки те, що явно позначили
export, і приходить лише те, що явно взяли через import.
Іменований експорт і імпорт
// файл: utils/format.ts
export function formatPrice(amount) { // export — видно назовні
return `${amount} грн`;
}
export const CURRENCY = 'UAH';
function round2(n) { // без export — внутрішня справа файлу
return Math.round(n * 100) / 100;
}
// файл: cart.ts
import { formatPrice, CURRENCY } from './utils/format';
formatPrice(250); // '250 грн'
round2(1.234); // ✗ ReferenceError — цього не експортували
У фігурних дужках — імена того, що береш. Вони мають збігатися з експортованими, але можна перейменувати:
import { formatPrice as price } from './utils/format'. Експортувати можна що завгодно: функції, класи,
константи, а в TypeScript ще й типи та інтерфейси.
Звідки імпортують: шлях чи пакет
| Запис | Що означає |
|---|---|
'./task' | файл task.ts у тій самій теці |
'../shared/date' | на теку вище, потім у shared/date.ts |
'@angular/core' | пакет із node_modules — встановлений через npm |
'rxjs' | так само пакет: бібліотека RxJS |
Правило розрізнення: шлях починається з крапки — це твій файл. Без крапки — пакет, який npm поклав у
node_modules. Розширення .ts не пишуть: збірка знайде файл сама.
import(): файл компонента завантажиться лише тоді, коли користувач відкриє його сторінку.export default — і чому в Angular його майже немає
export default class Dashboard { … } // «головне» з файлу, без імені в дужках
import Dashboard from './dashboard'; // імпорт без фігурних дужок, імʼя — будь-яке
Default-експорт можна імпортувати під будь-яким імʼям, і саме це його недолік: у різних файлах той самий клас
називатимуть по-різному, пошук і перейменування в редакторі працюють гірше. Тому в Angular-проєктах майже завжди
пишуть іменовані експорти. Якщо бачиш import X from без дужок — це default.
Модуль виконується один раз
Скільки б файлів не імпортували модуль, його код виконується лише при першому імпорті, а всі інші отримують той самий результат. Якщо в модулі є змінна, вона спільна для всіх, хто його імпортував. В Angular для спільного стану є сервіси (модуль 2), але принцип «один екземпляр на всіх» — звідси.
import() — завантажити файл тоді, коли треба
Звичайний import стоїть на початку файлу, і все потрібне завантажується одразу. Але буває функція
import('./шлях'): вона завантажує модуль на вимогу й повертає Promise — обіцянку, що модуль колись
буде готовий. Що таке Promise і .then, детально пояснює Ф2. Поки що досить знати:
.then(m => …) викличе стрілку, коли модуль завантажиться, і передасть його в m.
// з уроку про роутинг у модулі 2:
{
path: 'dashboard',
loadComponent: () => import('./features/dashboard/dashboard').then(m => m.Dashboard),
}
Тепер цей рядок читається повністю: «коли користувач піде на /dashboard, завантаж файл дашборду,
а з модуля візьми експортований клас Dashboard». Так Angular не тягне весь застосунок на першому
відкритті — це і є lazy loading.
- Забули
export— імпорт падає з помилкою «has no exported member». - Відносний шлях без крапки:
'utils/format'замість'./utils/format'— збірка шукатиме пакет. - Default і іменований переплутано:
import { Dashboard }для default-експорту або навпаки. - Два файли імпортують один одного (циклічна залежність) — дивні
undefinedна старті. Виносиш спільне в третій файл.
Підсумок
- Файл-модуль — окрема область видимості. Назовні лише
export, всередину лишеimport. - Шлях з крапкою — твій файл, без крапки — пакет із
node_modules. - В Angular пишуть іменовані експорти, default трапляється рідко.
import('./…')завантажує модуль на вимогу й повертає Promise — на цьому стоїть lazy loading маршрутів.