Angular 19 здесь, что нового?

Всем привет🤝, меня зовут Данила и я разработчик на Ангуляр. Далеко не все успели мигрировать на 18-ю версию, а тут ребята из тёплого Саннивилла радуют нас новой версией любимого фреймфорка. Давайте разбираться, что появилось!

routerOutletData

Теперь можно передавать данные родительскому компоненту RouterOutlet, что упрощает обмен данными из родительского компонента с его вложенными дочерними элементами.

Затем в дочернем компоненте вы можете получить данные через DI и токен ROUTER_OUTLET_DATA:

readonly userModel = inject>(ROUTER_OUTLET_DATA);

Service Workers

В поддержку сервис-воркеров в Angular было добавлено несколько функций.

Во-первых, теперь можно указать maxAgeдля всего приложения с помощью новой опции конфигурации под названием applicationMaxAge. Это позволяет нам настроить, как долго сервис-воркер будет кэшировать любые запросы. В пределах applicationMaxAgeфайлы будут обслуживаться из кэша. Все запросы будут обслуживаться только из сети, это может быть особенно полезно для index.html, чтобы гарантировать последнюю версию приложения, а не старую кэшированную версию, если пользователь пользовался приложением ранее.

{  "applicationMaxAge": "1d6h" // 1 день и 6 часов}

Во-вторых, появилась возможность определять refreshAhead задержку для конкретной группы данных. Когда время до истечения срока действия кэшированного ресурса меньше этой refreshAheadзадержки, Angular обновляет ресурс.

{  "dataGroups": [    {      "name": "api-books",      "urls": ["/api/books/**"],      "cacheConfig": {        "maxAge": "1d",        "timeout": "10s",        "refreshAhead": "10m"      }    }  ]}

Запрос и ответ через DI

Теперь получить доступ к объектам запроса и ответа в компонентах во время SSR стало легче благодаря новым токенам в @angular/core:

  • REQUESTдля доступа к текущему объекту HTTP-запроса

  • REQUEST_CONTEXTдля передачи пользовательских метаданных или контекста, связанного с текущим запросом, при рендеринге на стороне сервера

  • RESPONSE_INITдля доступа к опциям инициализации ответа

Гидратация

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

  • Частичная гидратация: отдает приоритет загрузке критически важных компонентов, сокращая начальное время взаимодействия

  • Инкрементная гидратация: откладывает загрузку функций на основе взаимодействия с пользователем (щелчков или наведений), оптимизируя использование ресурсов

Эти методы позволят создавать более быстрые и интерактивные приложения, улучшая взаимодействие с пользователем.

ng generate component --export-default

Новая опция изменяет компонент на использование синтаксиса экспорта по умолчанию: export default class AuthComponent. Это может быть интересно для компонентов с отложенной загрузкой:

loadComponent: () => import('./auth/auth.component')// вместо обычногоloadComponent: () => import('./auth/auth.component').then(m => m.AuthComponent)

Строгий CSP

В команду добавлен новый параметр, ng buildпозволяющий включить строгую политику безопасности контента (CSP) в сгенерированном index.htmlфайле. Этот параметр применяет рекомендации из этой статьи Web.dev и включает автоматическое создание CSP на основе хэша на основе сценариев в index.htmlфайле.

{  "security.autoCsp": true // angular.json}

Неиспользованный импорт

В компилятор Angular добавлена ​ расширенная диагностика, позволяющая обнаруживать неиспользуемый импорт в автономных компонентах!

Если вы забудете удалить импорт после рефакторинга кода, вы увидите такое сообщение:

TS-998113: Imports array contains unused imports [plugin angular-compiler]src/app/user/users.component.ts:14:27:  14 │   imports: [UserComponent, UnusedComponent],                                  ~~~~~~~~~~~~~~~

Signal API

Почти все Signal API стали стабильными (effect, toObservable и toSignal всё ещё нестабильны). Для удобства разработчиков сделали автомиграцию, выглядит это так (по отзывам, работает довольно хорошо)

ng generate @angular/core:signals? Which migrations do you want to run? (Press  to select,  to toggle all,  to invert selection, and  to proceed)❯◉ Convert `@Input` to the signal-based `input` ◉ Convert `@Output` to the new `output` function ◉ Convert `@ViewChild`/`@ViewChildren` and `@ContentChild`/`@ContentChildren` to the signal-based `viewChild`/`viewChildren` and  `contentChild`/`contentChildren`

Все эффекты больше не обрабатываются одинаково. Angular различает два типа эффектов:

Эффекты компонентов теперь запускаются во время обнаружения изменений (непосредственно перед фактическим обнаружением изменений хост-компонента), а не после него, как это было раньше. Таким образом, вы можете увидеть некоторые изменения в их поведении, например, когда эффект запускается изменением сигнала запроса представления. Чтобы решить эту проблему, была добавлена ​​новая функция afterRenderEffect. Она похож на effect, но её функция выполняется после рендеринга, а не до него. Как afterRenderи afterNextRender, она также может указывать, что должно выполняться на каждой фазе рендеринга, но значения передаются от фазы к фазе как сигналы, а не как простые значения. В результате более поздние этапы могут не выполняться, если значения, возвращенные более ранними этапами, не изменяются. afterRenderфункции еще находятся в предварительной версии для разработчиков.

Корневые эффекты не привязаны к жизненному циклу компонента и обычно используются для синхронизации состояния приложения с внешним миром (например, для записи его в локальное хранилище). Эти эффекты выполняются не как часть обнаружения изменений, а как микрозадача (и могут быть активированы в тестах с использованием TestBed.flushEffects()).

Ресурсы

Resources API является экспериментальным и скоро пройдет процедуру RFC: я бы пока не советовал вам его использовать.

Функция resourceпринимает объект с обязательной функцией-загрузчиком, которая возвращает обещание:

list(): ResourceRef | undefined> {  return resource({  loader: async () => {    const response = await fetch('/books');      return (await response.json()) as Array;    }  });}

В этом примере используется не HTTP-клиент, а собственная fetch()функция, возвращающая обещание. Действительно, resource()функция не связана с RxJS и поэтому может использовать любой клиент, возвращающий обещания. rxResourceявляется альтернативой resource, его можно использовать с клиентом на основе Observable. Это пример отделения Angular от RxJS, но при этом обеспечивающего функции взаимодействия, позволяющие беспрепятственно его использовать.

Функция возвращает ResourceRefобъект, содержащий:

  • сигнал isLoading, указывающий, загружается ли ресурс;

  • сигнал value, содержащий результат обещания;

  • сигнал error, содержащий ошибку, если обещание отклонено;

  • сигнал status, который содержит статус ресурса.

Затем вы можете использовать эти сигналы в своем шаблоне:

@if (booksResource.isLoading()) {  

Loading...

} @else { @for (book of booksResource.value(); track book.id) {

{{ book.name }}

}}

Сигнал statusможет быть:

  • ResourceStatus.Idle, исходное состояние

  • ResourceStatus.Loading, когда обещание находится на рассмотрении

  • ResourceStatus.Error, когда обещание отклонено

  • ResourceStatus.Resolved, когда обещание выполнено

  • ResourceStatus.Reloading, когда ресурс перезагружается

  • ResourceStatus.Local, когда значение установлено локально

Ресурс также имеет reloadметод, позволяющий перезагрузить ресурс. В этом случае его статус будет установлен на ResourceStatus.Reloading.

*_INITIALIZER токены устарели

Вместо токена APP_INITIALIZERтеперь нужно использовать provideAppInitializer. Эта новая функция — более элегантный способ предоставить инициализатор вашему приложению.

До версии 19 вы могли бы предоставить такой инициализатор:

{  provide: APP_INITIALIZER,  useValue: () => inject(InitService).init(),  multi: true},

Теперь вам нужно использовать provideAppInitializer:

provideAppInitializer(() => inject(InitService).init())

ENVIRONMENT_INITIALIZERи PLATFORM_INITIALIZERтакже устарели в пользу provideEnvironmentInitializerи providePlatformInitializer.
Руками ничего менять не нужно, автомиграция позаботится об этом =)

Шаблоны

Синтаксис @let теперь стабилен. Выражения в шаблоне теперь могут использовать typeofоператор:

@if (typeof user === 'object') {}

У пайпа keyvalueтакже есть новая опция. Этот пайп перебирать записи объекта. Но, как это ни удивительно, он по умолчанию упорядочивает записи по их ключу. Вы уже могли передать функцию сравнения, но теперь вы можете передать null,чтобы отключить упорядочивание:

@for (entry of bookModel() | keyvalue: null; track entry.key) {  
{{ entry.key }}: {{ entry.value }}
}

HMR и сборка

Hot Module Replacement теперь по-умолчанию работает и для стилей, теперь не нужно каждый раз обновлять страницу вручную. Общее время сборки, в целом, подтянули.

ng build --optimization=true --build-cache // сборка с кешем

Ведётся работа по улучшению HMR для шаблонов, уже можно попробовать в бета режиме (шаблоны будут перезагружены, обновив все экземпляры компонентов, без перезагрузки страницы, а состояние приложения сохранится):

 NG_HMR_TEMPLATES=1 ng serve

Оставшиеся изменения

  • Поддержка TypeScript 5.6

  • standalone: true теперь по-умолчанию

  • withEventReplay() для SSR теперь стабильна

  • Добавили связанные сигналы

Заключение

19-я версия содержит в себе действительно много новинок и улучшений, которые улучшают DX. Теперь окончательно ясно, что вектор развития на ближайшие пару лет это SSR, сигналы и standalone-компоненты.

Готовы к обновлению? Тогда вперёд!

ng update @angular/core @angular/cli

От себя рекомендую посмотреть официальное видео, ребята старались и, к тому же, продакшен на высоте:

Материал опубликован при поддержке сайта habr.com
Комментарии

    Актуальные новости по теме "Array"