Ось твій урок про Angular Modules, згенерований у стилі CS50: енергійно, з аналогіями та акцентом на розумінні "навіщо".
🎓 УРОК: Angular Modules — Архітектура вашого застосунку
Привіт, друзі! Мене звати [Твоє Ім'я], і це... CS50: Angular Edition.
Сьогодні ми не просто пишемо код. Сьогодні ми стаємо архітекторами.
1. 🔥 Вступ: Проблема «Звалища»
Уявіть собі ситуацію. Ви вирішили відкрити супермаркет. У вас є тисячі товарів: молоко, телевізори, шкарпетки, бензопили, яблука.
І ось ви скидаєте це все у одну величезну купу посеред зали.
Я ставлю вам просте запитання: Як швидко покупець знайде там пакет молока? І друге питання: Що станеться, коли ви привезете ще 5000 нових товарів?
Хаос. Це буде повний хаос.
У світі Angular, якщо ми не використовуємо Модулі (або сучасну альтернативу — Standalone API, про яку згодом), наш додаток перетворюється на таку саму купу. Компоненти, пайпи, директиви — все валяється в одному місці.
Навіщо нам ця тема? 1. Порядок: Щоб відділ "Молочка" був окремо від відділу "Електроніка". 2. Продуктивність: Щоб не завантажувати клієнту весь супермаркет, коли він прийшов лише за хлібом (це називається Lazy Loading). 3. Співпраця: Щоб один розробник міг працювати над "Адмінкою", не ламаючи "Кошик покупця".
Сьогодні ми навчимося розкладати цей хаос по поличках.
2. 🧠 Теоретична база: Що таке NgModule?
Давайте заглянемо під капот.
У Angular Модуль (NgModule) — це, по суті, коробка з етикеткою. Це контейнер, який гуртує пов’язані частини коду (компоненти, сервіси тощо) в одну функціональну одиницю.
В кожному модулі є спеціальний декоратор @NgModule(), який містить "інструкцію до коробки".
4 кити, на яких тримається модуль (це треба запам'ятати):
-
declarations(Оголошення):- Аналогія: Це список працівників вашого відділу.
- Тут ви перераховуєте компоненти, які "живуть" у цьому модулі. Якщо ви не оголосите компонент тут, Angular не знатиме про його існування.
-
imports(Імпорт):- Аналогія: Це інструменти, які ваш відділ позичає в інших відділів.
- Якщо вашому компоненту потрібні форми, ви імпортуєте
FormsModule. Якщо потрібен HTTP —HttpClientModule.
-
exports(Експорт):- Аналогія: Це вітрина вашого відділу.
- За замовчуванням, усе, що є в модулі — приватне (інкапсульоване). Якщо ви хочете, щоб інші частини програми могли використовувати ваш крутий
ButtonComponent, ви мусите додати його вexports.
-
providers(Провайдери):- Аналогія: Служба підтримки.
- Тут підключаються сервіси. (Хоча в сучасному Angular ми частіше використовуємо
providedIn: 'root', знати про це поле все ще важливо для легасі-коду).
💡 Інтуїтивне розуміння: Модуль — це як LEGO-набір. У ньому є інструкція (
declarations), детальки з інших наборів (imports) і готова модель, яку ви можете поставити на стіл (exports).
3. 🧪 Приклади: Від простого до реального
Приклад 1: Кореневий модуль (AppModule)
Кожен Angular-додаток (до ери Standalone) починається звідси.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent // 1. Оголошуємо наш головний компонент
],
imports: [
BrowserModule // 2. Імпортуємо базові інструменти браузера
],
providers: [],
bootstrap: [AppComponent] // 3. Стартуємо додаток з цього компонента
})
export class AppModule { }
Питання до вас: Чому AppComponent є в declarations, але немає в exports?
(Пауза для роздумів)
Відповідь: Тому що це кореневий модуль! Його ніхто не імпортує, він сам запускає додаток через bootstrap.
Приклад 2: Feature Module (Модуль функціоналу)
Уявіть, що ми робимо сайт з продажу піци. Створимо PizzaModule.
@NgModule({
declarations: [
PizzaListComponent, // Список піц
PizzaCardComponent, // Картка однієї піци
SecretSauceComponent // Секретний компонент (тільки для внутрішнього використання!)
],
imports: [
CommonModule // Потрібен для *ngIf та *ngFor
],
exports: [
PizzaListComponent // Ми дозволяємо іншим використовувати ТІЛЬКИ список
// PizzaCardComponent і SecretSauceComponent залишаються приватними!
]
})
export class PizzaModule { }
Що тут відбулося?
Ми створили "чорну скриньку". Зовнішній світ (наприклад, AppModule) може використовувати <app-pizza-list>, але він поняття не має про існування <app-secret-sauce>. Це і є інкапсуляція.
Приклад 3: Підключення модулів
Тепер AppModule хоче використовувати нашу піцу.
import { PizzaModule } from './pizza/pizza.module';
@NgModule({
imports: [
BrowserModule,
PizzaModule // <--- Ми підключили модуль піци сюди
],
// ...
})
export class AppModule { }
Питання на засипку: Якщо я в AppComponent (який живе в AppModule) спробую використати тег <app-secret-sauce>, що скаже Angular?
Результат: Він видасть помилку! ❌
"Component is not part of any NgModule or the module has not been imported..."
Чому? Тому що PizzaModule не додав SecretSauceComponent у свій масив exports.
4. 🛠 Практична частина
А тепер — руки на клавіатуру! Ось ваші завдання.
🔹 Завдання 1: Створення бази
Створіть новий модуль SharedModule. Оголосіть у ньому простий компонент HeaderComponent.
🔹 Завдання 2: Експорт/Імпорт
Спробуйте використати <app-header> у вашому AppComponent.
Очікування: Ви отримаєте помилку.
Дія: Додайте HeaderComponent в exports вашого SharedModule, а сам SharedModule імпортуйте в AppModule. Переконайтеся, що запрацювало.
🔹 Завдання 3: "Приватна вечірка"
Створіть у SharedModule компонент InternalHelperComponent. Використайте його всередині HeaderComponent. Але не експортуйте його. Перевірте, чи працює Header? (Має працювати). Спробуйте вставити InternalHelper в AppComponent. (Має впасти).
🔹 Завдання 4: Міні-кейс "User Profile"
Створіть модуль UserModule. У ньому мають бути:
1. LoginComponent (доступний зовні).
2. SettingsComponent (доступний тільки для LoginComponent або інших внутрішніх частин).
3. Підключіть UserModule до головного модуля.
🔹 Питання "А що, якщо..."
Що станеться, якщо ми імпортуємо BrowserModule двічі (в AppModule і в UserModule)?
(Спойлер: Angular сваритиметься. У дочірніх модулях треба використовувати CommonModule, а BrowserModule — тільки в головному).
5. 💡 Мислення як у розробника
Як думає Senior Developer, коли створює модулі?
-
Принцип єдиної відповідальності (SRP): Новачок кидає все в
AppModule. Профі створює окремі модулі:AuthModule(авторизація),ProductModule(товари),SharedModule(кнопки, інпути, які юзають всі). -
Уникнення "Shared Hell": Помилка новачків — створити один гігантський
SharedModuleі пхати туди все підряд. З часом він стає таким важким, що гальмує весь додаток. Порада: ТримайтеSharedModuleлегким. Тільки те, що справді використовується скрізь. -
Standalone Components (Сучасний погляд): Ви можете спитати: "Девід, я чув, що в Angular 15+ модулі необов'язкові?" Так! Це правда. Standalone Components дозволяють компонентам жити без модулів. АЛЕ:
- 90% існуючих проектів написані на модулях.
- Принципи групування та інкапсуляції, які ви вивчили сьогодні, однакові і там, і там.
- Розуміння модулів — це база для розуміння Архітектури.
6. 🧩 Підсумок
Отже, що ми сьогодні зробили? Ми перетворили звалище коду на структурований склад.
- Ми знаємо, що
declarations— це наші "працівники". - Ми знаємо, що
imports— це наші "інструменти". - Ми знаємо, що
exports— це наш "публічний інтерфейс".
Тепер ви вмієте: ✅ Розбивати додаток на логічні частини. ✅ Ховати внутрішню логіку (інкапсуляція). ✅ Перевикористовувати код між різними частинами програми.
Що далі? Уявіть, що у вас 50 модулів. Завантажувати їх усі одразу при запуску сайту — це довго. На наступному уроці ми поговоримо про Lazy Loading (Ліниве завантаження) через Routing. Ми навчимо Angular завантажувати модуль "Адмінка" тільки тоді, коли користувач справді туди клікне.
Це був CS50. Щасти вам з кодом!