Вийшов 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? Кидайте фото в коментарі 🙃

👍ПодобаєтьсяСподобалось9
До обраногоВ обраному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

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

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

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