[Перевод] Встречаем Angular 17
Эта статья — перевод оригинальной статьи «Introducing Angular v17».
Также я веду телеграм канал «Frontend по-флотски», где рассказываю про интересные вещи из мира разработки интерфейсов.
Вступление
В прошлом месяце исполнилось 13 лет с момента появления «красного щита» Angular. AngularJS стал отправной точкой для новой волны JavaScript-фреймворков, появившихся для поддержки растущей потребности в богатом веб-опыте. Сегодня с новым внешним видом и набором перспективных функций мы ведем всех в будущее с версией 17, устанавливая новые стандарты производительности и удобства для разработчиков.

В v17 мы рады представить:
Deferrable views выводят производительность и удобство работы разработчика на новый уровень
В публичных бенчмарках время выполнения со встроенным циклом контроля потока увеличивается на 90%.
Ускорение сборки до 87% для гибридного рендеринга и до 67% для рендеринга на стороне клиента
Новый свежий вид, отражающий перспективные возможности Angular
Совершенно новый интерактивный курс обучения
…и десятки других возможностей и улучшений!
Дизайн, ориентированный на будущее
Возрождение Angular идет полным ходом в течение последних нескольких версий. Мы набираем обороты благодаря таким улучшениям, как реактивность на основе сигналов, гидратация, автономные компоненты, композиция директив и десятки других возможностей. Несмотря на стремительное развитие Angular, его брендинг не смог догнать нас — он был практически одинаковым с первых дней существования AngularJS.
Сегодня любимый фреймворк, проверенный миллионами разработчиков, приобретает новый облик, отражающий его перспективность и производительность!

Документация, ориентированная на будущее
Вместе с новым брендом мы также разработали новый дом для документации по Angular — angular.dev. На новом сайте документации мы создали новую структуру, новые руководства, улучшили содержание и создали платформу для интерактивного обучения, которая позволит вам изучать Angular и Angular CLI в удобном для вас темпе, прямо в браузере.
Новый интерактивный учебный процесс основан на WebContainers и позволяет использовать возможности Angular CLI в любом современном веб-браузере!

Сегодня мы запускаем бета-версию angular.dev и планируем сделать его сайтом по умолчанию для Angular в версии 18. Подробнее о новом облике Angular и angular.dev вы можете узнать из статьи «Анонс angular.dev».
А теперь позвольте мне перейти к рассмотрению функций из v17, о которых нам не терпится рассказать вам!
Встроенный контроль потока
Чтобы улучшить работу разработчиков, мы выпустили новый синтаксис шаблонов блоков, который предоставляет мощные возможности с простыми, декларативными API. Под капотом компилятор Angular преобразует синтаксис в эффективные инструкции JavaScript, которые могут выполнять контроль потока, ленивую загрузку и многое другое.
Мы использовали новый синтаксис блоков для оптимизации встроенного контроля потока. Проведя исследования пользователей, мы обнаружили, что многие разработчики испытывают трудности с *ngIf, *ngSwitch и *ngFor. Работая с Angular с 2016 года и являясь частью команды Angular на протяжении последних 5 лет, я лично до сих пор вынужден искать синтаксис *ngFor и trackBy. Собрав отзывы сообщества, партнеров и проведя UX-исследования, мы разработали новый встроенный контроль потока для Angular!
Встроенный контроль поток позволяет:
Более эргономичный синтаксис, приближенный к JavaScript, а значит, более интуитивно понятный, требующий меньшего количества обращений к документации
Улучшенная проверка типов благодаря более оптимальному сужению типов
Это концепция, которая в первую очередь существует во время сборки, что позволяет сократить занимаемое место во время выполнения (сделать его «исчезающим»), что может уменьшить размер вашего пакета до 30 килобайт и дополнительно улучшить показатели Core Web Vital.
Он автоматически доступен в ваших шаблонах без дополнительного импорта
Значительные улучшения производительности, о которых мы расскажем чуть позже
Условные операторы
Рассмотрим сравнение с *ngIf:
The user is logged in
The user is not logged in
С помощью встроенного оператора if это условие будет иметь вид:
@if (loggedIn) {
Пользователь вошел в систему
} @else {
Пользователь не вошел в систему
}
Возможность напрямую предоставлять содержимое @else — это значительное упрощение по сравнению с пунктом else устаревшей альтернативы *ngIf. Текущий контроль потока также делает тривиальным наличие @else if, что исторически было невозможно.
Улучшение эргономики еще более заметно при использовании *ngSwitch:
который со встроенным контролем потоком превращается в:
@switch (accessLevel) {
@case ('admin') { }
@case ('moderator') { }
@default { }
}
Новый контроль потока позволяет значительно улучшить сужение типов в отдельных ветвях в @switch, что невозможно в *ngSwitch.
Встроенный цикл for
Одно из моих самых любимых обновлений — это встроенный цикл for, который, помимо улучшений в работе разработчиков, выводит скорость рендеринга Angular на новый уровень!
Его основной синтаксис таков:
@for (user of users; track user.id) {
{{ user.name }}
} @empty {
Empty list of users
}
Мы часто наблюдаем проблемы с производительностью в приложениях из-за отсутствия функции trackBy в *ngFor. Отличия @for заключаются в том, что функция trackBy является обязательной для обеспечения быстрой работы функции diffing. Кроме того, его гораздо проще использовать, поскольку это просто выражение, а не метод в классе компонента. Встроенный цикл @for также имеет возможность быстрого использования для коллекций с нулевыми элементами с помощью необязательного блока @empty.
Оператор @for использует новый diffing алгоритм и имеет более оптимальную реализацию по сравнению с *ngFor, что позволяет ему на 90% ускорить время выполнения в бенчмарках сообщества!

Попробуйте!
Встроенный контроль потока доступен в v17 в предварительной версии для разработчиков уже сегодня!
Одной из целей разработки встроенного контроля потока была возможность полностью автоматизированной миграции. Чтобы опробовать его в существующих проектах, воспользуйтесь следующей миграцией:
ng generate @angular/core:control-flow
Что дальше?
Вы уже можете использовать встроенный контроль поток с последней языковой версией сервиса, и мы тесно сотрудничали с компанией JetBrains, чтобы обеспечить лучшую поддержку в их продуктах. Мы также поддерживаем контакт с Sosuke Suzuki из Prettier, чтобы обеспечить правильное форматирование шаблонов Angular.
По сравнению с *ngIf, *ngFor и *ngSwitch все еще существуют некоторые различия в том, как встроенный контроль потока обрабатывает выделение содержимого, и мы будем работать над ними в течение следующих месяцев. Кроме того, мы уверены в его реализации и стабильности, так что вы можете попробовать его уже сегодня! Мы хотели бы оставить его в состоянии предварительного просмотра разработчиками до следующего крупного релиза, чтобы открыть дверь для потенциальных исправлений обратной несовместимости в случае, если мы найдем возможности для дальнейшего улучшения работы разработчиков.
Deferrable views
Теперь давайте поговорим о будущем ленивой загрузки! Используя новый синтаксис блоков, мы разработали новый мощный механизм, который можно использовать для ускорения работы приложений. В начале статьи я сказал, что deferrable views выводят производительность и удобство разработчиков на новый уровень, поскольку они обеспечивают декларативную и мощную отложенную загрузку с беспрецедентной эргономикой.

Предположим, у вас есть блог, и вы хотите лениво загружать список комментариев пользователей. В настоящее время приходится использовать ViewContainerRef, при этом приходится решать все сложные задачи по очистке, устранению ошибок при загрузке, показу заполнителя и т.д. Забота о различных угловых случаях может привести к появлению нетривиального кода, который будет сложно тестировать и отлаживать.
Новые откладываемые представления позволяют лениво загрузить список комментариев и все их транзитивные зависимости одной строкой декларативного кода:
@defer {
}
Самое невероятное заключается в том, что все это происходит посредством преобразования во время компиляции: Angular абстрагируется от всех сложностей, находя компоненты, директивы и пайпы, используемые внутри блока @defer, генерируя динамический импорт и управляя процессом загрузки и переключения между состояниями.
Ленивая загрузка компонента при попадании определенного DOM-элемента в область просмотра требует много более нетривиальной логики и использования API IntersectionObserver. Angular делает использование IntersectionObservers таким же простым, как добавление deferrable view триггера!
@defer (on viewport) {
} @placeholder {
}
В приведенном примере Angular сначала отображает содержимое блока placeholder. Когда он становится видимым в области просмотра, начинается загрузка компонента . По завершении загрузки Angular удаляет placeholder и отображает компонент.
Также имеются блоки для загрузки и состояния ошибки:
@defer (on viewport) {
} @loading {
Loading…
} @error {
Loading failed :(
} @placeholder {
}
Вот и все! Под капотом находится множество сложностей, которыми Angular управляет за вас.
Deferrable views предлагают еще несколько триггеров:
on Idle— ленивая загрузка блока, когда браузер не выполняет никакой тяжелой работыon immediate— начать ленивую автоматическую загрузку, не блокируя браузерon timer(— задержка загрузки с помощью таймераon viewportиon viewport()— viewport также позволяет указать ссылку на якорный элемент. Когда элемент якоря становится видимым, Angular лениво загрузит компонент и отрендерит егоon interactionиon interaction()— позволяет инициировать ленивую загрузку при взаимодействии пользователя с определенным элементомon hoverиon hover()— запускает ленивую загрузку, когда пользователь наводит курсор на элементwhen— позволяет задать собственное условие через выражение, возвращающее обещание
Deferrable views также предоставляют возможность предварительной выборки зависимостей перед их отрисовкой. Добавить предварительную выборку так же просто, как добавить оператор prefetch в блок defer и поддерживать все те же триггеры.
@defer (on viewport; prefetch on idle) {
}
Deferrable views доступны в предварительной версии для разработчиков в v17 уже сегодня! Подробнее об этой функции можно узнать из этого руководства.
Что дальше?
Откладываемые представления уже готовы к использованию, и мы настоятельно рекомендуем вам попробовать их! Причина, по которой мы оставляем их в предварительной версии для разработчиков, заключается в том, что мы можем собрать больше отзывов и внести изменения в поверхность API до тех пор, пока не переведем их на семантическое версионирование, как и остальную часть фреймворка.
В настоящее время при рендеринге на стороне сервера отображается указанный placeholder. Как только фреймворк загрузит приложение и гидратирует его, deferrable views будут работать так, как мы описали выше.
В качестве следующего шага мы рассмотрим возможность рендеринга содержимого внутри блока defer на сервере и включения частичной гидратации на клиенте. В этом случае клиент не будет загружать код deferrable view до тех пор, пока триггер не запросит его. В этот момент Angular загрузит связанный JavaScript и гидратирует только эту часть представления.
Также будет много интересных возможностей взаимодействия с сигналами, так что следите за новостями!
Обновленный опыт гибридного рендеринга
Сегодня мы приближаем серверный рендеринг (SSR) и генерацию статических сайтов (SSG или prerendering) к разработчикам с помощью подсказки в ng new:

Это изменение мы хотели внести уже давно, но сначала мы хотели быть уверены в том, что разработчики Angular смогут использовать SSR.
Кроме того, вы можете включить SSR в новых проектах с помощью:
ng new my-app --ssr
Гидратация выведена из предварительной версии для разработчиков
За последние 6 месяцев мы увидели тысячи приложений, использующих технологию гидратации. Сегодня мы рады сообщить, что гидратация вышла из предварительной версии для разработчиков и включена по умолчанию во всех новых приложениях, использующих рендеринг на стороне сервера!
Новый пакет @angular/ssr
Мы перенесли репозиторий Angular Universal в репозиторий Angular CLI и сделали рендеринг на стороне сервера еще более неотъемлемой частью нашего инструментария!
Начиная с сегодняшнего дня, чтобы добавить поддержку гибридного рендеринга в существующее приложение, выполните следующие действия:
ng add @angular/ssr
Эта команда сгенерирует точку входа в сервер, добавит возможности сборки SSR и SSG, а также включит гидратацию по умолчанию. @angular/ssr предоставляет функциональность, эквивалентную @nguniversal/express-engine, который в настоящее время находится в статусе поддержки. Если вы используете express-engine, Angular CLI автоматически обновит ваш код до @angular/ssr.
Компания Virgin Media O2 отметила рост продаж на 112% после перехода на новейшее решение для гибридного рендеринга Angular Hybrid с устаревшей платформы. При использовании NgOptimizedImage в сочетании с Angular SSR с DOM Hydration среднее снижение кумулятивного сдвига макета составило 99,4%.
Развертывание вашего приложения с SSR
Чтобы еще больше повысить удобство работы разработчиков, мы тесно сотрудничаем с облачными провайдерами, обеспечивая плавное развертывание на их платформах. Теперь
Firebase автоматически распознает и развертывает ваше Angular-приложение практически без конфигурации, благодаря ранней предварительной версии нового CLIENTS с поддержкой фреймворка.
firebase experiments:enable webframeworks
firebase init hosting
firebase deploy
CLI с учетом фреймворка распознает использование SSR, i18n, оптимизацию изображений и многое другое, позволяя обслуживать производительные веб-приложения на экономичной бессерверной инфраструктуре.
Для тех, кто имеет сложные моноресурсы Angular или просто предпочитает нативные инструменты, AngularFire позволяет развертывать приложения на Firebase с помощью ng deploy:
ng add @angular/fire
ng deploy
Чтобы обеспечить развертывание на edge воркерах, мы включили поддержку модулей ECMAScript в серверный рендеринг Angular, внедрили бэкенд fetch для HttpClient и работали с CloudFlare над оптимизацией процесса.
Новые хуки жизненного цикла
Для повышения производительности SSR и SSG Angular в долгосрочной перспективе мы хотели бы отказаться от эмуляции DOM и прямых манипуляций с DOM. В то же время на протяжении жизненного цикла большинства приложений им необходимо взаимодействовать с элементами для инстанцирования сторонних библиотек, измерения размера элементов и т.д.
Для этого мы разработали набор новых хуков жизненного цикла:
afterRender— регистрирует обратный вызов, который будет вызываться каждый раз, когда приложение завершает рендеринг-afterNextRender— регистрирует обратный вызов, который будет вызван в следующий раз, когда приложение завершит рендеринг
Эти крючки будут вызываться только браузером, что позволяет безопасно подключать пользовательскую DOM-логику непосредственно внутри компонентов. Например, если вы хотите создать библиотеку графиков, вы можете использовать afterNextRender:
@Component({
selector: 'my-chart-cmp',
template: `{{ ... }}`,
})
export class MyChartCmp {
@ViewChild('chart') chartRef: ElementRef;
chart: MyChart|null;
constructor() {
afterNextRender(() => {
this.chart = new MyChart(this.chartRef.nativeElement);
}, {phase: AfterRenderPhase.Write});
}
}
Каждый хук поддерживает значение phase (например, чтение, запись), которое Angular будет использовать для планирования обратных вызовов, чтобы уменьшить количество ошибок в компоновке и повысить производительность.
Vite и esbuild по умолчанию для новых проектов

Мы не смогли бы включить SSR в Angular с самого начала, если бы не фундаментальные изменения, внесенные нами в конвейер сборки Angular CLI!
В версии 16 мы представили разработчикам предварительную версию сборки esbuild plus Vite powered build. С тех пор многие разработчики экспериментировали с ним, а некоторые корпоративные партнеры сообщили об улучшении времени сборки некоторых приложений на 67%! Сегодня мы рады сообщить, что новый сборщик приложений вышел из предварительной версии и теперь включен по умолчанию для всех новых приложений!
Кроме того, мы обновили конвейер сборки при использовании гибридного рендеринга. С помощью SSR и SSG вы можете наблюдать до 87% прироста скорости в ng build и 80% ускорения цикла редактирования-обновления в for ng serve.

В одной из следующих минорных версий мы выложим схему автоматической миграции существующих проектов, использующих гибридный рендеринг (рендеринг на стороне клиента с SSG или SSR). Если вы хотите протестировать новый конструктор приложений уже сегодня, обратитесь к этому руководству в нашей документации.
Отладка инъекции зависимостей в DevTools
В прошлом году мы показали предварительную версию возможностей отладки инъекций зависимостей в Angular DevTools. За последние несколько месяцев мы реализовали совершенно новые отладочные API, позволяющие подключаться к среде выполнения фреймворка и инспектировать дерево инжекторов.
На основе этих API мы создали пользовательский интерфейс, позволяющий просматривать дерево инжекторов:
Зависимости ваших компонентов в инспекторе компонентов
Дерево инжекторов и путь разрешения зависимостей
Провайдеры, объявленные в отдельных инжекторах
Быстрый предварительный просмотр функций представлен на анимации ниже. Подробнее об Angular DevTools можно узнать на сайте angular.io.

В качестве следующего шага мы отполируем пользовательский интерфейс и поработаем над улучшением визуализации иерархий инжекторов, провайдеров и их разрешения.
Standalone API с самого начала
Собрав за последние полтора года отзывы об standalone компонентах, директивах и пайпах и отшлифовав их в DevEx, мы уверены, что теперь они будут включены во все новые приложения с самого начала. Все команды ng generate теперь будут использовать standalone компоненты, директивы и пайпы.
Вместе с этим мы также пересмотрели всю документацию на angular.io и angular.dev, чтобы обеспечить единообразие в обучении, практике разработки и рекомендациях.
Мы сохраним NgModules в обозримом будущем, но, видя преимущества новых standalone API, мы настоятельно рекомендуем постепенно переводить на них свои проекты. Мы также предлагаем схему, которая позволит автоматизировать большую часть этой работы:
ng generate @angular/core:standalone
Для получения дополнительной информации ознакомьтесь с нашим руководством по миграции.
Следующие шаги в области реактивности
Новая реактивная система Angular, основанная на сигналах, стала одним из самых значительных изменений, которые мы сделали во фреймворке. Чтобы обеспечить обратную совместимость и взаимодействие с системой обнаружения изменений на основе Zone.js, мы много работали над прототипами и проектированием дальнейших действий.
Сегодня мы рады сообщить, что реализация Angular Signals вышла из стадии предварительного просмотра разработчиками. Пока что мы оставим функцию effect в предварительной версии для разработчиков, чтобы иметь возможность доработать ее семантику.
В ближайшие пару месяцев мы начнем внедрять такие функции, как входные данные на основе сигналов, запросы к представлению и многое другое. К маю следующего года в Angular v18 мы получим множество функций, которые еще больше улучшат работу разработчиков с сигналами.
Дальнейшие шаги по тестированию
Мы продолжаем экспериментировать с Jest и убеждаемся, что создаем решение, которое будет достаточно производительным, гибким и интуитивно понятным, чтобы удовлетворить потребности разработчиков. Мы также начинаем экспериментировать с Web Test Runner и открыли PR для его первоначальной реализации. В ближайшем будущем мы, скорее всего, сосредоточимся на Web Test Runner, чтобы разблокировать проекты, желающие перейти с Karma.
Следующие шаги для Material 3
Совместно с командой Material Design компании Google мы активно работаем над рефакторингом внутренних компонентов Angular Material с целью внедрения маркеров дизайна — системы, предоставляющей значительно больше возможностей для настройки компонентов и обеспечивающей поддержку Material 3. Хотя мы еще не готовы к внедрению маркеров дизайна и поддержки M3 в v17, мы ожидаем, что эти функции появятся в ближайшее время в минорном выпуске v17.
В IV квартале 2022 года мы объявили о выпуске новых компонентов Angular Material на базе MDC и об отказе от старых компонентов, которые имеют эквивалентную функциональность, но отличаются структурой и стилями DOM. В v15 мы отказались от устаревших компонентов, которые будут удалены в v17. Несмотря на то, что они не будут входить в пакет Angular Material v17, вы можете обновить свои приложения до Angular v17 и использовать пакет Angular Material v16. Такая возможность будет действовать до версии 18, после чего Angular Material v16 перестанет быть совместимым с новыми версиями Angular. Мы также сотрудничаем с нашими партнерами из HeroDevs, которые собираются предложить платную постоянную поддержку в случае, если вы пока не можете выполнить миграцию.
Улучшение качества жизни
Вместе с этими перспективными функциями мы отправили на рынок ряд небольших улучшений для разработчиков!
Экспериментальная поддержка View Transitions
View Transitions API обеспечивает плавные переходы при изменении DOM. В маршрутизаторе Angular мы теперь обеспечиваем прямую поддержку этого API с помощью функции withViewTransitions. С ее помощью можно использовать встроенные возможности браузера для создания анимированных переходов между маршрутами.
Вы можете добавить эту функцию в свое приложение уже сегодня, настроив ее в объявлении провайдера маршрутизатора во время бутстрапа:
bootstrapApplication(App, {
providers: [
provideRouter(routes, withViewTransitions()),
]
});
withViewTransitions принимает необязательный объект конфигурации со свойством onViewTransitionCreated, которое представляет собой обратный вызов, обеспечивающий дополнительный контроль:
Решите, хотите ли вы пропустить определенные анимации
Добавьте в документ классы для настройки анимации и удалите эти классы по завершении анимации
и так далее
Автоматическое предварительное подключение в директиве image
Директива Angular image теперь автоматически генерирует ссылки предварительного соединения для доменов, которые вы указали в качестве аргумента загрузчику изображений. Если директива image не может автоматически определить источник и не обнаруживает предварительную ссылку для LCP-изображения, то во время разработки она выдаст предупреждение.
Подробнее об этой возможности можно узнать из руководства по работе с директивой image.
Отложенная загрузка модуля анимации
Эта возможность позволяет сэкономить 60 КБ от начального пакета (16 КБ в gzipped). Участник сообщества Matthieu Riegler предложил и реализовал функцию, позволяющую лениво загружать модуль анимации через асинхронную функцию провайдера:
import { provideAnimationsAsync } from '@angular/platform-browser/animations-async';
bootstrapApplication(RootCmp, {
providers: [provideAnimationsAsync()]
});
Преобразования входных значений
Часто встречается компонент, который получает на вход булевое значение. Это, однако, накладывает ограничения на то, как можно передать значение такому компоненту. Например, если у нас есть следующее определение компонента Expander:
@Component({
standalone: true,
selector: 'my-expander',
template: `…`
})
export class Expander {
@Input() expanded: boolean = false;
}
…и мы стараемся использовать его как:
При этом будет выдана ошибка «string is not assignable to boolean». Преобразования входных значений позволяют исправить это, настроив декоратор ввода:
@Component({
standalone: true,
selector: 'my-expander',
template: `…`
})
export class Expander {
@Input({ transform: booleanAttribute }) expanded: boolean = false;
}
Оригинальные запросы функций можно найти на GitHub — Boolean properties as HTML binary attributes и Boolean properties as HTML binary attributes.
Style и styleUrls как строки
Компоненты Angular поддерживают несколько таблиц стилей для каждого компонента. Однако в подавляющем большинстве случаев, когда я хочу придать стиль своим компонентам, я создаю массив с одним элементом, указывающим на встроенные стили или ссылающимся на внешнюю таблицу стилей. Новая функция позволяет переключаться с:
@Component({
styles: [`
...
`]
})
...
@Component({
styleUrls: ['styles.css']
})
...
…к более простому и логичному:
@Component({
styles: `
...
`
})
...
@Component({
styleUrl: 'styles.css'
})
...
Мы по-прежнему поддерживаем несколько таблиц стилей при использовании массива. Это более эргономично, интуитивно понятно и лучше сочетается с инструментами автоматического форматирования.
Схемы сообществ
Для поддержки разработки схем сообщества мы добавили несколько методов-утилит в рамках @schematics/angular/utility. Теперь вы можете импортировать выражение непосредственно в корень приложения Angular и добавить провайдер в корень приложения Angular, а также воспользоваться уже существующей возможностью добавления зависимостей в package.json.
Более подробную информацию можно получить в руководстве по схемам в документации.
Обучение разработчиков Angular
Мы сотрудничали с SoloLearn, интерактивной платформой EdTech, для разработки нового курса по Angular на основе недавно разработанного нами курса «Введение в Angular». Они создали интерактивный учебный курс, который за последние два месяца посетили более 70 тыс. человек!

Более подробная информация содержится в нашем недавнем сообщении.
Яркие моменты деятельности сообщества
Мы хотели бы поблагодарить 346 участников, которые сделали Angular v17 таким особенным! Мы хотели бы перечислить несколько наиболее ярких моментов:
Построение будущего с Angular
В течение последних шести месяцев мы продолжаем возрождать Angular, выпуская новые функции для повышения удобства работы разработчиков и производительности. Сегодня мы рады отразить эту динамику в обновленном бренде Angular и учебном опыте с angular.dev.
В следующем цикле релизов ожидается большое развитие реактивности Angular на основе сигналов, гибридного рендеринга и обучения.
Мы гордимся тем, что являемся частью вашего путешествия по созданию будущего с помощью Angular! Спасибо!
