Вийшов Angular 20: розбираємося, що нового

💡 Усі статті, обговорення, новини про Front-end — в одному місці. Приєднуйтесь до Front-end спільноти!

Команда Angular випустила 20-ту версію фреймворку. У цьому релізі багато змін, які спрощують розробку і роблять інструменти більш сучасними. Давайте глянемо, що саме змінилося.

Нові експериментальні API в Angular

Щоб краще працювати з асинхронними даними, команда Angular ще у версії 19 додала resource API, а в Angular 20 розширила цю можливість — тепер з’явилися resource streaming та httpResource.

Приклад: завантаження користувача

const userId: Signal<string> = getUserId();
const userResource = resource({
  params: () => ({ id: userId() }),
  loader: ({ request, abortSignal }) => {
    return fetch(`users/${request.id}`, { signal: abortSignal });
  },
});

Цей код автоматично підвантажує користувача, коли змінюється userId.

Приклад: стрімінг даних через WebSocket

@Component({
  template: `{{ dataStream.value() }}`
})
export class App {
  dataStream = resource({
    stream: () => {
      return new Promise(resolve => {
        const resourceResult = signal({ value: [] });
        this.socket.onmessage = event => {
          resourceResult.update(current => ({
            value: [...current.value, event.data]
          }));
        };
        resolve(resourceResult);
      });
    },
  });
}

Цей приклад показує, як працювати з потоковими даними — наприклад, із WebSocket. Кожне нове повідомлення додається у список, а UI оновлюється автоматично.

Приклад: httpResource для HTTP-запитів

@Component({
  template: `{{ userResource.value() | json }}`
})
class UserProfile {
  userId = signal(1);
  userResource = httpResource<User>(() =>
    `https://example.com/v1/users/${this.userId()}`
  );
}

Тут кожна зміна userId автоматично тригерить новий HTTP-запит. API повертає об’єкт з усім необхідним: value, isLoading, headers тощо.

Працює все на базі HttpClient, тому можна підключати інтерсептори:

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(
      withInterceptors([loggingInterceptor, cachingInterceptor])
    ),
  ],
});

Zoneless

Angular 20 зробив великий крок до так званого zoneless-режиму, де зміни в UI відслідковуються без zone.js. Це простіше, швидше і чистіше.

Додано:

  • Підтримку обробки глобальних помилок у Node.js (SSR): unhandledRejection, uncaughtException.
  • Глобальні слухачі помилок у браузері через provideBrowserGlobalErrorListeners/

Як підключити:

bootstrapApplication(AppComponent, {
  providers: [
    provideZonelessChangeDetection(),
    provideBrowserGlobalErrorListeners(),
  ],
});

Не забудьте прибрати zone.js із angular.json, якщо переходите на zoneless.

Стабільна серверна підтримка

Angular 20 зробив стабільними дві важливі фічі:

Інкрементальна гідратація (incremental hydration)

Завантажується лише те, що потрібно, а не весь DOM одразу:

import {
  provideClientHydration,
  withIncrementalHydration,
} from '@angular/platform-browser';
provideClientHydration(withIncrementalHydration());

Рендеринг на рівні маршрутів

Тепер можна задавати, як рендерити окремі маршрути: на сервері (SSR), на клієнті (CSR) або заздалегідь (Prerender):

export const routeConfig: ServerRoute = [
  { path: '/login', mode: RenderMode.Server },
  { path: '/dashboard', mode: RenderMode.Client },
  {
    path: '/product/:id',
    mode: RenderMode.Prerender,
    async getPrerenderParams() {
      const dataService = inject(ProductService);
      const ids = await dataService.getIds(); // ["1", "2", "3"]
      return ids.map(id => ({ id }));
    }
  }
];

Це дає змогу оптимізувати швидкість і UX кожного окремого маршруту.

Динамічне створення компонентів з директивами та байндингами

У версії 20 Angular нарешті дозволяє створювати компоненти динамічно — не просто з інпутами й аутпутами, а ще й з директивами та двосторонніми байндингами.

Приклад:

import { createComponent, signal, inputBinding, outputBinding, twoWayBinding } from '@angular/core';
const canClose = signal(false);
const title = signal('My dialog title');
createComponent(MyDialog, {
  bindings: [
    inputBinding('canClose', canClose),
    outputBinding<Result>('onClose', result => console.log(result)),
    twoWayBinding('title', title),
  ],
  directives: [
    FocusTrap,
    {
      type: HasColor,
      bindings: [inputBinding('color', () => 'red')],
    },
  ]
});

Простими словами: можна створити компонент на льоту, передати йому дані, додати потрібні директиви — і все це без зайвої мороки.

Шаблони стали ближчими до JavaScript

Тепер Angular підтримує нові вирази прямо в шаблонах:

  • Ступінь: {{ n ** 2 }}
  • Оператор in: {{ name in person }}

Шаблонні рядки:

<div [class]="`layout col-${colWidth}`"></div>

Це робить шаблони зрозумілішими для тих, хто звик до звичайного JavaScript.

Краще діагностування помилок

Angular почав ловити типові помилки ще на етапі розробки:

  • Використання ?? у невідповідному контексті
  • Забутий імпорт структурних директив (@if, @for)
  • І коли ви передаєте функцію trackFn у @for не викликаючи її
@for (user of users; track trackFn) {

  <!-- ... -->

}

Такого роду дрібниці тепер виявляються автоматично.

Покращена підтримка host bindings

Тепер можна вмикати перевірку типів для host у компонентах — просто додайте:

"angularCompilerOptions": {

  "typeCheckHostBindings": true

}

У версії 21 це буде вмикатися автоматично.

Тестування з Vitest

Angular офіційно експериментує з Vitest — сучасною альтернативою Karma. Підтримує watch mode, швидше працює, і взагалі набагато приємніший у використанні.

Щоб спробувати:

npm i vitest jsdom --save-dev

У angular.json:

"test": {
  "builder": "@angular/build:unit-test",
  "options": {
    "tsConfig": "tsconfig.spec.json",
    "buildTarget": "::development",
    "runner": "vitest"
  }
}

А у тестах:

import { describe, beforeEach, it, expect } from 'vitest';

І все — можна запускати ng test.

Material: кнопки стали ще кращими

Angular Material оновився відповідно до Material 3:

  • Зʼявилась тональна кнопка (tonal button) — виглядає сучасніше і краще вписується в дизайн.
  • Назви компонентів стали послідовнішими.
  • Зʼявився новий селектор matIconButton — щоб чітко вказувати, що це кнопка з іконкою.
  • Обʼєднано MatButton і MatAnchor — більше не треба імпортувати їх окремо.

Більше контролю в MatDialog і Overlay

У MatDialog зʼявився параметр closePredicate, який дозволяє вказати умови, за яких діалог можна закривати. Нарешті!

У Overlay — нові API, що краще працюють з tree-shaking. Тобто, у фінальний бандл потрапляє тільки те, що реально використовується.

Плавні анімації — або їх повна відсутність

Angular тепер поважає системне налаштування prefers-reduced-motion, що важливо для людей з чутливістю до руху.

А для повного вимкнення анімацій (наприклад, у тестах) можна використати спеціальний DI-токен.

Angular та ШІ

У новій версії зʼявився файл llms.txt, який допомагає LLM-ам (на кшталт ChatGPT) краще розуміти структуру проєкту й генерувати актуальний код.

Також відкрито розділ angular.dev/ai — тут гайди, приклади, best practices для інтеграції GenAI, Genkit, Vertex AI тощо.

Кінець епохи *ngIf і друзів

Все. Крапка. *ngIf, *ngFor, *ngSwitch офіційно застарілі.

Angular ще у v17 представив новий синтаксис:

  • @if, @for, @switch
  • Пишеться як у JavaScript
  • Не потребує імпорту директив
  • Працює швидше
  • Краще типізується

Щоб перейти на новий стиль, просто виконайте:

ng generate @angular/core:control-flow

Ця команда автоматично замінить старі конструкції у шаблонах.

І наостанок — Angular отримає власного маскота 🐟

Так, тепер у Angular буде талісман. Від «щита з очима» до симпатичної рибки-ліхтарика — команда розглядає різні варіанти. Можна долучитись до обговорення: запропонувати ідею, проголосувати чи навіть придумати ім’я.





Як думаєте, який маскот ідеально підійшов би Angular? Кидайте фото в коментарі 🙃

👍ПодобаєтьсяСподобалось10
До обраногоВ обраному3
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Ну дуже специфічний фреймворк. Поріг входу високий попит мізерний

не для «середніх розумів»

в мене розум нижче середнього, але якось на Angular пишу. це не про розум, а про системний підхід.

з пивом та ШІ покатить. я бекендщик якось скоро рік як на Angular — дійсно, вхід рубль, вихід — два. Але мене пре, бо це не реакт ну і + TypeScript

Поріг входу високий

Розумова відсталість?

попит мізерний

Можливо в Україні? Трохи західніше лінії Керзона в компаніях, де більше 10 людей, роботи навалом.

про розумову відсталість свідчить настільки некоректна навіть не критика чужої думки, а засудження.

я свідчу — поріг входження високий. особливо для людей, які ніколи фронтом не займалися.

От дивіться, без образ.

в мене розум нижче середнього, але якось на Angular пишу

Якщо такий «складний» фреймворк освоїла людина, яка, за власним визнанням, не має видатних здібностей і відповідного досвіду, що це значить?.. Правильно. Це значить, що поріг входження низький.
Справу закрито.

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

Підписатись на коментарі