Обзор функций, которые Ivy предлагает нам сегодня, и взгляд на возможные функции, которые Ivy будет включать в будущих версиях Angular.
Недавно во время кофе я побеседовал с разработчиком об Angular 9. Я сказал ему, как я взволнован предстоящим выпуском. В частности, из-за Айви.
Несмотря на то, что он уже играл с Айви в версии 8, он не мог понять моего волнения.
«Вся эта шумиха по поводу немного меньших пакетов!»
Что ж, это еще не все. Давайте разберемся, почему мне нравится Айви и почему вам тоже?
Да, у нас бывают пакеты поменьше
Начнем с функции, о которой знает большинство разработчиков. С Ivy мы получаем пакеты меньшего размера. На прошлогодней конференции ng-conf команда Angular представила некоторые статистические данные, которые показывают, как Ivy уменьшает размер пакета по сравнению с ViewEngine.
При переходе на Ivy мы получаем пакеты меньшего размера бесплатно! Довольно круто. Но как получилось? Хорошо. Потому что мы зовем Айви!
Основная идея Ivy: инвертирование
Ivy сильно отличается от ViewEngine.
ViewEngine использует все функции Angular и выполняет итерацию нашего кода. В зависимости от используемых нами функций Angular выполняет требуемый код фреймворка.
Айви инвертирует поведение ViewEngine.
Ivy, с другой стороны, компилирует наш HTML в инструкции JavaScript, которые задействуют возможности Angular.
Давайте проанализируем это поведение дальше, посмотрев на скомпилированный Ivy шаблон компонента Angular.
Айви сохраняет код нашего компонента и добавляет к нему фабрику. Кроме того, он добавляет все необходимые метаданные компонента, такие как selectors
, inputs
, outputs
и т. Д. Все метаданные остаются локальными для компонента (Locality).
Однако самая интересная часть заключается в функции template
. Функция template
отображает нашу DOM. Он состоит из двух фаз, которые представлены параметром rf
. На первом этапе создается шаблон, элементы записываются на страницу. На втором этапе разрешаются привязки шаблонов.
Код внутри функции шаблона создает DOM, вызывая инструкции Ivy. Это существенное изменение по сравнению с ViewEngine - это то, что улучшает размер нашего пакета. Как придешь?
"Если вы хотите включить встряхивание дерева, вам нужно четко указать свои намерения"
Выполняя инструкции Ivy, наш код очень четко сообщает о своих намерениях и, следовательно, может быть проанализирован с помощью шейкер дерева. Теперь шейкер деревьев знает, какие части Angular мы будем использовать, а какие нет.
Благодаря этому изменению механизм встряхивания дерева может вытряхнуть неподготовленные детали. Короче говоря, Angular сам по себе становится нестабильным.
Хорошо, это круто. Но пока что мы наблюдаем только улучшение размера пакета. (Что, кстати, на мой взгляд, уже достаточно, чтобы быть в восторге от Айви! 😉)
Ленивая загрузка компонентов с помощью Ivy 🌱
Еще одна замечательная функция, которую Ivy предлагает нам сегодня: ленивая загрузка компонента.
Ленивая загрузка компонента? 🤔 Вы имеете в виду ленивую загрузку модулей, не так ли? Нет, я имею в виду ленивую загрузку компонентов.
В текущих версиях Angular модули можно лениво загружать с помощью роутера Angular. Как только пользователь попадает на ленивый маршрут, Angular загружает необходимый фрагмент кода в отдельном запросе.
В настоящее время отложенная загрузка возможна только на уровне модуля. С Ivy мы получаем более тонкий контроль над отложенной загрузкой.
Представьте, что у нас есть приложение Quiz. Мы хотим динамически загружать QuizCardComponent
, когда пользователь запускает викторину.
Как только пользователь нажимает «Начать тест», мы продолжаем и получаем наш QuizCardComponent
. После загрузки мы динамически добавляем компонент в контейнер. С этого момента мы можем взаимодействовать с компонентом.
С Ivy отложенная загрузка компонента может быть достигнута с помощью синтаксиса EcmaScript import
.
Оператор import
возвращает нам Promise
. Как только это Promise
разрешается, мы получаем экземпляр компонента.
Это общая идея. Конечно, с помощью приведенного выше фрагмента вы пока не можете реализовать продуктивный компонент с отложенной загрузкой. Это еще не все, особенно если вы начнете использовать сторонние компоненты, такие как Angular material.
Не волнуйся. Если вы хотите узнать, как написать продуктивный компонент с отложенной загрузкой, использующий материал Angular, ознакомьтесь с моей статьей «Компоненты с отложенной загрузкой в Angular».
Может вы думаете; Довольно круто. Но как часто я буду использовать эту функцию? Ленивая загрузка на уровне модуля уже довольно хороша.
Хорошо. Я вижу, вы еще не очень взволнованы. Давайте посмотрим на следующую функцию, которую Ivy предлагает нам сегодня.
Улучшенная отладка - летающий нг
Благодаря тому, как Ivy компилирует наши шаблоны, улучшена поддержка отладки. Особенно опыт отладки в нашем браузере.
Айви показывает объект ng
. Этот объект «летает» в нашей консоли. Мы можем использовать его во время выполнения, чтобы получить экземпляр компонента. Как только мы получили конкретный экземпляр компонента, мы можем начать манипулировать им.
Для этого мы открываем наш проводник DOM и используем символ стрелки в верхнем левом углу наших инструментов разработчика, чтобы выбрать нужный компонент.
Мы можем использовать $0
, чтобы получить ссылку на текущий узел DOM. Используя ng.getComponent($0)
, мы получаем наш компонент.
В этой игре-викторине пользователь должен угадать город. Показанный выше город - Берн. Но мы манипулируем нашим QuizCardComponent
с помощью инструментов ng и меняем correctAnswer
на QuizCardComponent
на «Dublin».
Когда мы нажимаем на Берн, мы видим, что QuizCardComponent
показывает красный цвет, чтобы указать, что наш ответ был неправильным, и отображает правильный ответ, Дублин (который не является правильным).
Мы можем манипулировать нашими компонентами во время выполнения в браузере! Довольно мило. Вы уже в восторге от Айви? Нет? Лучшее еще впереди! Возможности, которые Айви предлагает в будущем!
До сих пор мы говорили о функциях, которые мы можем использовать уже сегодня. На мой взгляд, самое важное в Ivy - это возможности, которые он предлагает на будущее.
Ivy - залог будущего Angular
⚠️ Внимание! Все API, используемые в примерах, являются частными или так называемыми API для поиска острых ощущений. Они еще не являются официально поддерживаемыми API. Их будущее неясно. Они могут появиться или не появиться в будущих версиях Angular.
ɵrenderComponent
Помните изображение размера пакета в начале этого сообщения? Может быть, вам было интересно, как мы можем увеличить размер нашего пакета до 14KB
и что означает API «Thrill seekers»?
API для любителей острых ощущений - это экспериментальный и еще не завершенный API. Также пока не ясно, будет ли он доработан в будущих версиях или нет. Все API для поиска острых ощущений в Angular используют префикс дельты (ɵ).
Хотя API для «любителей острых ощущений» еще не доработаны, мы уже можем использовать их и экспериментировать. Поскольку они содержат префикс дельты (ɵ), который, кстати, никто не знает, как набирать текст на клавиатуре, 😉 Я рекомендую использовать псевдоним импорта.
import {ɵrenderComponent as renderComponent} from '@angular/core';
Ok. Давайте посмотрим, что мы можем сделать с renderComponent
. Что ж, мы можем визуализировать компонент. 😊
Обычно мы запускаем наше приложение Angular с функцией bootstrapModule
. Давайте прокомментируем текущий подход к начальной загрузке и воспользуемся взамен renderComponent
.
Если мы запустим ng serve
, мы не заметим разницы; все работает как раньше. Даже без NgModule
. Однако существенная разница заключается в размере нашего пакета, который сейчас уменьшился до 23 KB
. Gzip мы бы даже приземлились под 10 KB
.
renderComponent
- это способ получить действительно небольшие пакеты.
Но как renderComponent
знает, где рендерить наш AppComponent
?
Что ж, у нас все еще есть селектор в нашей DOM, мы используем тег <app-root>
в нашем index.html
. Если у нас есть такой selectorrenderComponent
отрисовывает компонент непосредственно в селектор.
ɵrenderComponent в сочетании с отложенной загрузкой
Компонент рендеринга удобен и в других случаях использования. Например, с ленивой загрузкой компонентов.
renderComponent
принимает дополнительное свойство opts
. Эти параметры позволяют нам передать host
, где должен быть прикреплен наш компонент, а также injector
, чтобы наш компонент мог использовать преимущества DI.
Это важно, когда мы лениво загружаем наш компонент. В сценарии с отложенной загрузкой у нас нет селектора в нашей DOM; поэтому нам нужно свойство host
.
ɵrenderComponent для веб-компонентов
renderComponent
дает нам новые возможности в создании веб-компонентов. Это позволяет нам писать крошечные веб-компоненты размером около 10 KB
размера пакетов. Какой размер подходит для большинства случаев использования.
Давайте быстро посмотрим, как можно реализовать простой переключатель в качестве веб-компонента.
Чтобы предоставить этот компонент как веб-компонент, Ivy позволяет нам написать для этого класс элемента.
Класс SliderElement
расширяет HTMLElement
. После выполнения constructor
этого класса мы используем метод renderComponent
, чтобы сообщить Ivy, что он должен отобразить наш SliderComponent
в этот CustomElement.
Метод renderComponent
возвращает нам экземпляр компонента. Мы используем этот экземпляр, чтобы реагировать на @Outputs
или передавать @Inputs
нашему компоненту. Передача входных данных проста, однако, когда мы реагируем на @Outputs
, мы подписываемся на поток и используем метод dispatchEvent
для отправки CustomEvent
.
После того, как мы настроили наш SliderElement
, нам все равно нужно определить его как настраиваемый элемент в нашем main.ts
.
customElements.define('my-slider-element', SliderElement);
Большой! Теперь мы можем взаимодействовать с нашим веб-компонентом, используя простой HTML. Если мы можем взаимодействовать с компонентом, используя стандартные API-интерфейсы DOM, мы гарантируем, что мы также можем взаимодействовать с этими компонентами с помощью других фреймворков.
А как насчет NgModules? 📦
Модули являются неотъемлемой частью каждого приложения Angular. В ViewEngine они содержат все необходимые метаданные для существования компонента. Однако в предыдущем примере мы смогли визуализировать компонент без использования модуля. Модули становятся необязательными?
Чтобы ответить на этот вопрос, давайте взглянем на компонент, скомпилированный с Ivy.
Ранее мы видели, что Айви вводит понятие под названием «местность». Это означает, что все метаданные являются локальными для компонента. Другими словами, Айви не волнует NgModule
. Ivy использует метаданные directives
, чтобы узнать о зависимостях компонента.
directives: [_hello_component__WEBPACK_IMPORTED_MODULEselectors
_["HelloComponent"]],
В настоящее время Ivy знает об этом, поскольку извлекает информацию из файла NgModule
. Однако в будущих версиях Angular может иметь общедоступный API для объявления зависимостей непосредственно от компонента. Есть несколько предложений.
1. Группирование компонентов в массив
Одна из идей состоит в том, чтобы указать все компоненты в массиве, а затем использовать оператор распространения, чтобы добавить их в массив компонентов directives
.
Ларс Гайруп Бринк Нильсен провел отличный семинар о дополнительных модулях NgModules. Рекомендую вам это проверить:
Укажите Deps на компоненте
Минко Гечев из команды Angular предложил решение, которое позволяет нам указывать зависимости от декоратора компонентов.
Опять же, это предложения, и пока неизвестно, как они попадут в Angular.
Компоненты высшего порядка
Концепция «высшего порядка» - это то, что мы уже знаем из других вариантов использования, например, из наблюдаемых более высокого порядка или функций высшего порядка.
Функции высшего порядка, вероятно, являются самым простым способом объяснить эту концепцию:
Функции высшего порядка - это функции, которые принимают другие функции в качестве аргументов или возвращают функции в качестве своих результатов.
Хорошо известным примером функции высшего порядка является функция отображения массивов. Если бы мы реализовали функцию карты самостоятельно, мы выполняем сопоставление в соответствии с функцией projection
, которую мы принимаем в качестве параметра.
Функции высшего порядка позволяют нам использовать композицию. Мы можем создать несколько небольших функций и скомпоновать их в более сложную функцию.
То же самое относится и к компонентам. Компоненты более высокого порядка - это компоненты, которые возвращают новые компоненты. Давайте рассмотрим вариант использования, в котором будут иметь смысл компоненты более высокого порядка.
Начнем с простого компонента, отображающего имя.
Это тупой компонент, потому что его не волнует, откуда взялся name
, он только его показывает.
Глупые компоненты - неотъемлемая часть любого приложения Angular. Они заботятся только об отображении @Inputs
и испускании @Outputs
. Но сами по себе они не очень полезны. Обычно внутри интеллектуального компонента используются «глупые» компоненты.
Что, если мы хотим использовать HelloComponent
в нескольких местах, где потребуется доступ к имени из QueryParams
в маршруте. Может быть, у нас даже есть PriceComponent
, который делает то же самое, но получает цену от price
QueryParam
вместо name
QueryParam
. Нам нужно будет написать много дублированного кода.
Здесь нам может помочь идея компонента более высокого порядка.
У нас есть функция с именем displayQueryParam
, которая принимает компонент. Внутри этой функции мы создаем компонент более высокого порядка. В ловушке жизненного цикла ngOnInit
этого компонента мы читаем все QueryParams
.
Самое интересное тогда происходит внутри функции template
. В функции шаблона мы должны динамически создавать экземпляр компонента, который мы передали методу displayQueryParam
. Затем мы должны использовать метаданные компонента, чтобы проверить, соответствует ли один из QueryParams
свойству @Input
. Если это так, мы передадим это значение компоненту.
Поскольку это официально не поддерживается, написание этого кода в настоящее время очень сложно. Но мы не хотим слишком углубляться в детали; Я просто хочу показать концепцию.
После того, как мы реализовали наши HigherOrderComponent
и displayQueryParma
функции, мы могли бы использовать их в наших маршрутах.
Это отобразит HelloComponent
и отобразит свойство name
из маршрута. С PriceComponent
он отобразит свойство price
из QueryParams
.
Обнаружение изменений без зоны
В настоящее время Zone.js
является неотъемлемой частью автоматического обнаружения изменений. Хотя это не требуется для самого обнаружения изменений. Zone js monkey исправляет асинхронные события браузера. Как только такое событие происходит, он уведомляет Angular о запуске обнаружения изменений.
Однако у Zone.js
есть несколько недостатков. Во-первых, его размер составляет около 100 KB
. Это ограничитель для веб-компонентов. Несмотря на то, что мы можем уменьшить наш пакет до размера 10 KB
, вам все равно потребуется отправить 100 KB
из Zone.js
, чтобы функция обнаружения изменений работала. Другой большой недостаток состоит в том, что Zone.js
не может исправлять собственные инструкции async/await
.
Как помогает Айви?
Что ж, Айви представляет функцию markDirty
. Функция markDirty
принимает компонент в качестве ссылки. Затем он помечает этот компонент как грязный и запускает обнаружение изменений. Функция markDirty
также гарантирует, что обнаружение изменений не запускается слишком часто.
Толкать трубу
«Беззонные» подходы используют преимущества markDirty
API. Одно из предложений - реализовать канал push
, который был бы очень похож на уже известный канал async
. Разница в том, что под капотом используется markDirty
вместо markForCheck
.
{{ someStream$ | push }}
Реактивные компоненты
Майк Райан выступил с отличным докладом на прошлогодней конференции AngularConnect в Лондоне. Он глубоко погрузился в функцию markDirty
и представил идею ReactiveComponent, который запускает обнаружение изменений, когда поток передает значение.
Расширение ReactiveComponent
даст намconnect
метод для запуска Обнаружения изменений, как только наш поток испускает значение.
Заключение
Плющ - это самая интересная вещь в грядущем выпуске Angular. Ivy предлагает нам множество замечательных функций, которые мы уже можем использовать с Angular 9.
- Меньшие пакеты из коробки
- Ленивая загрузка компонентов
- Улучшена отладка в браузере
Еще более захватывающим, чем те функции, которые мы можем использовать сегодня, является вид в будущем. Ivy открывает много возможностей для будущего Angular. Некоторые могут перейти на Angular, а некоторые нет. Пока неясно. Но Ivy предлагает следующие возможности.
renderComponent
- для крошечных связок- Маленькие веб-компоненты с помощью
renderComponent
- Необязательно
NgModules
- Компоненты высшего порядка
- Беззонное обнаружение изменений
Вы уже можете поиграть с API для любителей острых ощущений. Но не используйте их в производстве. Мы не знаем, дойдут ли эти функции до Angular.
🧞 🙏 Если вам понравился этот пост, поделитесь им и хлопните в ладоши👏🏻, нажав несколько раз на кнопку хлопка слева.
Хлопки помогают другим людям находить контент и мотивируют меня писать больше 😉
Не стесняйтесь ознакомиться с некоторыми из моих других статей о фронтенд-разработке.