[Перевод] Встречаем 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! Спасибо!