Angularшлях до Strong Junior
Модулі / JavaScript: основа / Модулі: import і export
🔥 0

Фундамент Ф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 не пишуть: збірка знайде файл сама.

main.ts app.config.ts app.routes.ts task-list.ts task.service.ts NODE_MODULES: @angular/core · @angular/router · rxjs пунктир — import() за потреби
Стрілка — «імпортує». Кожен файл бере лише те, що йому потрібно. Пунктир — динамічний 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 маршрутів.