Автор материала, перевод которого мы публикуем, предлагает поговорить об 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 не займёт много времени и не потребует серьёзных усилий.
Тут можно найти пошаговые руководства по переходу на новые версии Angular.
Примерно месяц назад Игорь Минар говорил, что всё указывает на то, что Angular 8.0.0 вполне может выйти в конце мая. 24 мая вышел Angular 8.0.0-rc.5.
Будущее Angular выглядит достаточно оптимистичным. Всё остальное зависит от нас.
Уважаемые читатели! Чего вы ждёте от Angular 8?
Автор: ru_vds