Автор материала, перевод которого мы публикуем, предлагает поговорить об Angular 8. Здесь будут рассмотрены некоторые особенно горячие темы, поднятые на мероприятиях NgConf и Google I/O 2019. Поэтому, если вы интересуетесь Angular, но по каким-то причинам не видели докладов с этих мероприятий, полагаем, вам любопытно будет узнать о том, чего можно ждать от Angular 8.
Основные положения
Уверен, что вы сейчас, с нетерпением ожидая выхода Angular 8, испытываете те же чувства, что испытывал я после NgConf 2019. В докладе Игоря Минара затронуто множество ожидаемых новшеств — от инструментов до технологий вроде дифференциальной загрузки и многих других замечательных вещей.
Обсудим то, как всё это может повлиять на ваши проекты. А именно, рассмотрим новые возможности и поговорим о том, приведёт ли их появление к признанию устаревшими существующих механизмов, или к тому, что новое окажется несовместимым со старым.
Новые возможности
▍Дифференциальная загрузка
При применении технологии дифференциальной загрузки (differential loading), Angular, в процессе сборки проекта, может создать отдельный бандл для полифиллов (polyfills). Это зависит от файла browserlist
. Вот как это, в общих чертах, будет выглядеть.
Сверху — новый способ упаковки проектов (источник)
Использование этой возможности позволит уменьшить размеры бандлов.
Экономия благодаря применению дифференциальной загрузки (источник)
Как же это работает?
Angular будет собирать дополнительные файлы с полифиллами и они будут внедряться в код с помощью атрибутов nomodule:
<body>
<pp-root></pp-root>
<script type="text/javascript" src="runtime.js"></script>
<script type="text/javascript" src="es2015-polyfills.js" nomodule></script>
<script type="text/javascript" src="polyfills.js"></script>
<script type="text/javascript" src="styles.js"></script>
<script type="text/javascript" src="vendor.js"></script>
<script type="text/javascript" src="main.js"></script>
</body>
Атрибут nomodule
, логический, предотвращает загрузку и выполнение скрипта в браузерах, поддерживающих ES6-модули. Такие браузеры игнорируют подобные скрипты. Старые браузеры загружают и выполняют их.
▍SVG-шаблоны
Теперь SVG файлы можно будет использовать в качестве шаблонов. До сих пор в качестве шаблонов можно было использовать встроенный или внешний HTML-код.
@Component({
selector: "app-icon",
templateUrl: "./icon.component.svg",
styleUrls: ["./icon.component.css"]
})
export class AppComponent {...}
▍Экспериментальный движок рендеринга Ivy
Движок Ivy всё ещё находится в экспериментальной стадии. После выхода Angular 8 его можно испытать, воспользовавшись при создании нового приложения флагом --enable-ivy
. Ниже показан соответствующий код. Помните о том, что Ivy пока ещё не вполне готов (он ещё находится в статусе «opt-in preview»), и, как сказал Игорь Минар на NgConf 2019, при создании новых приложений всё ещё рекомендуется использовать движок View Engine.
Для того чтобы включить использование Ivy в существующем проекте, нужно в файле tsconfig.app.json
установить в true
параметр enableIvyoption
в angularCompilerOptions
:
"angularCompilerOptions": {"enableIvy": true}
Можно и создать новое приложение, в котором будет использоваться Ivy:
$ ng new my-app --enable-ivy
Ivy предлагает следующие полезные возможности, появление трёх первых из которых ожидается в Angular 9:
- Более быстрая компиляция.
- Улучшенная проверка типов для шаблонов.
- Уменьшение размеров бандлов. Вот, если вы ещё этого не видели, демонстрация приложения размером 4.3 Кб с Google I/O 19.
- Обратная совместимость.
- И моя любимая возможность — отладка шаблонов. Уверен, что, как и мне, это нужно многим разработчикам.
▍Поддержка Bazel
Bazel — это очередной инструмент, переведённый Google в разряд опенсорсных. Игорь Минар говорит, что Bazel долгое время использовался для внутренних нужд компании, а теперь он доступен всем. Для того чтобы узнать подробности об этом сборщике проектов — загляните в документацию и почитайте о том, как использовать Bazel с Angular.
Возможно, вы сейчас задаётесь вопросом о том, готов ли Bazel к практическому применению. Если кратко ответить на этот вопрос — то ещё не готов. Сейчас он пребывает в статусе «opt-in preview». Позволю себе процитировать Алекса Игла, который руководит в Google командой по разработке инструментов Angular: «Если вы уже входили в воды Bazel раньше, то не могли не заметить, что там было множество акул… Теперь с акулами уже справились, но вода всё ещё может оказаться холодной».
Bazel пока доводят до ума, ожидается, что его включат в @angular/cli
в версии 9.
Вот какие полезные возможности способен дать нам Bazel:
- Ускорение времени сборки проектов. Первая сборка занимает определённое время, но параллельные сборки выполняются гораздо быстрее. Angular уже использует Bazel, и теперь CI-процедуры завершаются за 7.5 минут, а не за час, как было до Bazel.
- Инкрементальная сборка проектов. Можно будет собирать и разворачивать не всё приложение, а лишь то, что в нём изменилось.
- Возможность работы с файлами Bazel, которые, по умолчанию, скрыты.
Добавить в существующий проект поддержку Bazel можно так:
ng add @angular/bazel
Можно и создать новое приложение с использованием Bazel:
$ npm install -g @angular/bazel
$ ng new my-app --collection=@angular/bazel
▍API Builders
Новая версия Angular позволяет использовать API Builders, известный так же как Architect. Angular использует сборщики (builder) для выполнения основных операций: serve
, build
, test
, lint
и e2e
. Вот пример использования сборщиков из файла angular.json
:
...
"projects": {
"app-name": {
...
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
...
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
...
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
...
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
...
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
...
}
}
}
}
Теперь можно создавать собственные сборщики. Мне они видятся подобными командам gulp/grunt, используемым в «прежние времена».
В целом, сборщик — это просто функция с набором команд, которую передают методу createBuilder()
из пакета @angular-devkit/architect
:
import { createBuilder } from '@angular-devkit/architect';
function customBuild(options, context) {
return new Promise((resolve, reject) => {
// набор команд
})
}
createBuilder(customBuild);
На встроенные сборщики Angular можно взглянуть здесь. Вот отличный материал о них в блоге Angular.
▍Изменения в ленивой загрузке
В новой версии Angular будет и новая версия системы ленивой загрузки модулей, появление которой приводит к тому, что существующий синтаксис loadChildren:string
будет признан устаревшим.
Раньше это выглядело так:
loadChildren: './lazy/lazy.module#LazyModule';
С выходом Angular 8 — так:
loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule)
Если у вас есть множество модулей, при работе с которыми применяется механизм ленивой загрузки, и вы хотите автоматизировать их перевод в новый режим работы — взгляните на этот материал.
▍Поддержка API $location AngularJS
Команда разработчиков Angular стремится к тому, чтобы поддержать тех, кто пользуется AngularJS и помочь им перейти на Angular. В результате в систему, в пакет angular/common/upgrade
, добавлена поддержка сервиса $location
. Речь идёт о следующих возможностях:
- Получение состояния от сервиса
$location
. - Отслеживание изменений адреса.
- Получение тех же сведений о составных частях адреса, которые можно было получить в AngularJS (
hostname
,protocol
,port
,search
). - Тестирование сервиса с помощью API MockPlatformLocation.
▍Веб-воркеры
В Angular 8 добавлена поддержка веб-воркеров. С их помощью можно организовать фоновое выполнение ресурсоёмкого кода. Для того чтобы создать новый веб-воркер можно воспользоваться следующей командой интерфейса командной строки Angular:
ng g webWorker <name>
▍Сервис-воркеры
Так как в последнее время наблюдается серьёзный рост популярности прогрессивных веб-приложений, было сделано множество улучшений сервис-воркеров. В частности, одним из таких улучшений стало добавление параметра SwRegistrationOptions
. Ещё одним улучшением стала поддержка нескольких приложений на одном домене.
Почитать подробности о сервис-воркерах можно в этом разделе документации Angular.
▍Улучшения форм
Добавлен метод markAllAsTouched
, который позволяет отметить все элементы внутри FormGroup
как touched
. Это весьма полезно в тех случаях, если нужно запустить валидацию всех элементов управления внутри FormGroup
. До этого то же самое делалось так:
validateFormAndDisplayErrors(form: FormGroup) {
Object.keys(form.controls).map((controlName) => {
form.get(controlName).markAsTouched({onlySelf: true});
});
}
В новом Angular для очистки FormArray
можно воспользоваться методом clear
, который удаляет из него все элементы. Ранее нужно было пользоваться следующей конструкцией, удаляя первый элемент в каждой итерации цикла:
while (formArray.length) {
formArray.removeAt(0);
}
Больше так делать не придётся. Теперь достаточно вызвать единственный метод:
formArray.clear()
▍Настройка момента получения ответа при использовании директив ViewChild и ContentChild
Эта новая возможность подразумевает использование флага static
, который позволяет указать момент разрешения запроса, определяемого директивой ViewChild
или ContentChild
.
Возможно, вы сталкивались со следующими примерами непоследовательного поведения системы. Иногда результаты поиска доступны в методе жизненного цикла ngOnInit
, а иногда их нет до вызова ngAfterContentInit
или ngAfterViewInit
. Вот как пользоваться флагом static
:
// Обеспечивает проведение обнаружения изменений перед предоставлением доступа к элементу
@ContentChild('foo', { static: false }) foo!: ElementRef;
// Позволяет получить доступ к элементу в методе жизненного цикла ngOnInit
@ViewChild(TemplateRef, { static: true }) foo!: TemplateRef;
Надо отметить, что эти возможности недоступны для директив ViewChildren
и ContentChildren
. Соответствующие им запросы на поиск элементов выполняются после выполнения обнаружения изменений.
При использовании static: true
стоит проявлять осторожность, так как применение этого флага не позволит получать результаты из динамических шаблонов (то есть *ngIf). В систему добавлено правило Schematics, позволяющее перевести существующий код на использование нового синтаксиса. Этот синтаксис будет использоваться с Ivy.
→ Подробности об этой возможности можно почитать здесь.
▍Поддержка Typescript 3.4.x
Angular теперь использует TypeScript 3.4 (в седьмой версии Angular применяется TypeScript 3.2.x). В новой версии TS не так уж и много серьёзных изменений. Они, вероятно, не приведут к неприятным последствиям.
→ Подробности о новшествах TS 3.4 можно узнать здесь.
▍Улучшение производительности
В текущих условиях ServerRendererFactory2
создаёт новый экземпляр DomElementSchemaRegistry
для каждого запроса, что довольно затратно в плане ресурсов. Теперь же будет организовано совместное использование глобального экземпляра DomElementSchemaRegistry
.
▍Развёртывание Angular-приложений на хостинге Firebase
Если вы пользуетесь
ng run [PROJECT_NAME]:deploy
→ Тут можно узнать подробности об этой возможности.
API, признанные устаревшими
▍Использование типа any при работе с TesBed.get
Метод TesBed.get
имел две сигнатуры. Одна — типизированная, вторая — принимающая и возвращающая тип any
. Теперь сигнатура метода, предусматривающая применение типа any
, признана устаревшей. Пользоваться этим методом можно только с указанием конкретного типа. Это, например, окажет воздействие на случаи работы со строковыми токенами (которые не поддерживаются) и с некоторыми другими токенами.
Раньше использовались такие конструкции:
TestBed.configureTestingModule({
providers: [{ provide: "stringToken", useValue: new Service() }],
});
let service = TestBed.get("stringToken"); // тип any
Теперь применяется следующий подход:
const SERVICE_TOKEN = new InjectionToken<Service>("SERVICE_TOKEN");
TestBed.configureTestingModule({
providers: [{provide: SERVICE_TOKEN, useValue: new Service()}],
});
let service = TestBed.get(SERVICE_TOKEN); // тип Service
▍Удаление DOCUMENT из angular/platform-browser
Из пакета @angular/platform-browser
удаляют DOCUMENT
. Если вы пользуетесь DOCUMENT
из этого пакета — вам стоит начать импортировать его из @angular/common
.
▍Удаление пакета angular/http
Пакет @angular/http
был признан устаревшим в Angular 5, но был всё ещё доступен, так как @angular/platform-server
был от него зависим. Теперь этот пакет удаляют из списка пакетов.
Критические изменения
▍Автоматическое исправление кода
Немногие знают о том, что Angular автоматически исправлял ошибки при использовании HTML-элементов tr
и col
.
В случае с tr
исправления выполнялись в том случае, если соответствующий элемент не находился внутри тега tbody
, tfoot
или thead
. Исправления заключались в автоматическом помещении элемента в tbody
.
В случае с col
исправлениям подвергался код, в котором этот элемент не находится внутри тега colgroup
.
Теперь Angular оставляет исправление этих ошибок на усмотрение разработчиков. Делается это для того чтобы избежать конфликтов и ошибок. Как результат, тем, кто привык к этой возможности, нужно будет заботиться о правильности кода самостоятельно.
→ Подробности об этом можно почитать здесь.
▍Переименование Angular Material
Проект Angular Material переименован в Angular Components. Имена пакетов не изменились.
Итоги
Angular 8 выйдет уже очень скоро. Команда разработчиков Angular делает большое дело. Результаты их усилий облегчают работу и жизнь тех, кто пользуется Angular. В частности, например, с каждой новой версией фреймворка всё проще и проще выполнять переход на неё с предыдущей версии. Вот, например, как это выглядит в случае с Air France.
Время, необходимое для перехода на новые версии Angular (источник)
В результате можно надеяться на то, что переход с Angular 7 на Angular 8 не займёт много времени и не потребует серьёзных усилий.
Автор: ru_vds