Пишем декораторы c Angular Ivy

Kliment Ru
Angular Soviet
Published in
4 min readJun 22, 2019

В восьмой версии Angular в экспериментальном режиме будет доступен новый движок рендеринга Ivy. Oдна из его возможностей — более гибкое создание собственных декораторов. Что такое декораторы и зачем их писать разберем в этой статье.

Декораторы

При написании кода большую часть функционала можно разделить на функции, компоненты или модули, но в некоторых случаях это невозможно.

Такую функциональность называют сквозной (от англ. scattered — разбросанный или англ. tangled — переплетённый), так как её реализация распределена по различным модулям программы. Сквозная функциональность приводит к рассредоточенному и запутанному коду, сложному для понимания и сопровождения.

Аспектно-ориентированное программирование

Для этих целей идеально подходит патерн декоратор:

Декоратор (англ. Decorator) — структурный шаблон проектирования, предназначенный для динамического подключения дополнительного поведения к объекту.

Шаблон Декоратор предоставляет гибкую альтернативу практике создания подклассов с целью расширения функциональности.

Говоря простыми словами, декоратор может добавлять к классу новые свойства и методы и запускать под капотом невидимые механизмы. Это позволяет делать сами компоненты более чистыми и читабельными и использовать в разработке принцип don’t repeat yourself (DRY), а вся магия происходит под капотом декоратора.

В JavaScript декораторы появились в ES2016 (Exploring EcmaScript Decorators). Декоратор — это функция, которую надо добавить перед классом свойством или методом со знаком @ . В Angular примерами декораторов являются: Component, Input, Output и т.д.

Вот как будет выглядеть простейший декоратор класса

Добавим декоратор, написанный выше, к Angular компоненту

И в консоли мы получим ссылку на класс компонента

Как это работает в IVY

В текущем движке Renderer 2 после компиляции приложения метаданные и фабрика для создания компонента хранятся отдельно от самого класса компонента, поэтому большинство параметров компонента недоступны для изменения в рантайме. С новым движком IVY после компиляции все метаданные попадают в статическое свойство класса компонента ngComponentDef, и с ними можно производить манипуляции до создания компонента.

Доработаем декоратор Logger, который будет логировать метаданные компонента. Также добавим к нему входной параметр tag. Для этого надо обернуть декоратор в функцию и через её аргументы передать входные данные

Вот что получим в консоли

Тут можно найти селектор, фабрику для создания компонента, шаблон, стили, хуки жизненного цикла и многое другое.

Декораторы для работы с хуками компонента

Как было сказано выше, хуки жизненного цикла можно получить через ngComponentDef. Разберем как можно с ними работать так же на примере логирования.

В первую очередь необходимо получить экземпляр компонента. Он пригодится ниже для привязки контекста к методам жизненного цикла. Делается это через подмену фабрики ngComponentDef.factory

Все хуки хранятся в метаданных компонента в методах onInit, onDestroy и т. д. Так же, как и с фабрикой, сохраняем оригинальный хук в константу, после чего подменяем его, добавляя нужный функционал. И тут же необходимо использовать созданный экземпляр компонента, для того чтоб привязать контекст через call или apply.

Работа с экземпляром компонента

Для манипуляций с данными компонента, как и в примере выше, необходимо создать его экземпляр и подменить оригинальную фабрику, которую использует Angular при создании компонента.

В этом примере мы будем логировать обращение к свойствам и методам компонента, поэтому нам понадобится еще объект Proxy

Прокси (proxy) — особый объект, смысл которого — перехватывать обращения к другому объекту и, при необходимости, модифицировать их.

Синтаксис:

let proxy = new Proxy(target, handler)

Здесь:

target – объект, обращения к которому надо перехватывать.

handler – объект с «ловушками»: функциями-перехватчиками для операций к target.

Проще говоря, прокси является прослойкой между конечным объектом и тем, кто к нему обращается, и при обращении может проверять и модернизировать данные.

Для того чтобы перехватить запись и чтение свойств и методов компонента, надо в декораторе:

  1. Создать экземпляр компонента;
  2. Сделать его proxy;
  3. Вернуть прокси в фабрике вместо оригинала.

Вот как выглядит перехват и логирование чтения свойств компонента

При логировании чтения методов принцип остается тот же. Только надо не забыть добавить проверку на то что это метод и через call или apply привязать к методу контекст this.

Вот что получим в консоли

Заключение

Декораторы действительно крутая фича. С их помощью можно красивее и элегантнее использовать такие вещи, как логирование, сторы для хранение данных, отписку при уничтожении компонента и другие вещи.

Будем ждать выхода Angular 8 и полноценной поддержки IVY.

--

--