Найти тему
Nuances of programming

Платформы Angular в деталях. Часть 1. Что такое платформы Angular?

Оглавление

Источник: Nuances of Programming

Инфраструктура для разработки приложений Angular была задумана как платформенно-независимая технология (далее по тексту — фреймворк). Такой подход позволяет запускать приложения на Angular в разных средах: в браузере, сервере, веб-воркере и даже на мобильных устройствах.

В данной серии статей я опишу, как это вообще возможно — запускать Angular-приложения в разных средах. Мы также научимся создавать пользовательскую платформу Angular, с помощью которой можно визуализировать приложения из терминала, используя графику ASCII.

Содержание

  • Angular — это кроссплатформенный фреймворк
  • Что такое платформы Angular?
  • Как платформы Angular делают возможным кроссплатформенный запуск приложений?

Angular — это кроссплатформенный фреймворк

Как было сказано выше, Angular была задумана платформенно-независимой инфраструктурой, в которую была заложена возможность вариативного применения. Благодаря этому, Angular является кроссплатформенным фреймворком, не ограничивающимся только браузером. Единственное, что необходимо для запуска приложений на Angular, — это движок JavaScript. Рассмотрим самые популярные рабочие среды Angular.

Браузер

Когда мы создаём новое приложение на Angular, используя Angular CLI ng new MyNewApplication, в качестве среды для нашего приложения по умолчанию используется браузер.

Сервер

Приложения на Angular могут компилироваться и запускаться на серверной стороне. В этом случае мы можем компилировать Angular-приложение в статические HTML-файлы и затем отправлять эти файлы клиентам.

Благодаря этому, мы можем ускорить загрузку приложений и заодно позаботиться о правильной индексации приложений всеми поисковыми системами.

Веб-воркер

Также мы можем перетащить часть Angular-приложения в отдельный поток. В фоновый поток веб-воркер. В этом случае в основном потоке остаётся лишь малая часть приложения, обеспечивающая взаимодействие части, находящейся в веб-вокере, с API-интерфейсом документа.

Благодаря этому подходу, пользовательский интерфейс улучшается, очищаясь от «мусора», так как большая часть работы приложения проходит теперь за его пределами.

Web worker с самого начала была экспериментальной средой, и к моменту появления Angular 8 она устарела.

NativeScript

Кроме того, существует множество сторонних библиотек, позволяющих запускать Angular-приложения в разных средах. Например, NativeScript, который делает возможным запуск Angular на мобильных устройствах с использованием всей функциональности их собственных платформ.

Но как это вообще возможно — запускать Angular-приложения в разных средах?

Ответ — платформы!

Что такое платформы Angular?

Чтобы разобраться, что такое платформы Angular, надо обратиться к точке входа любого Angular-приложения — файлу main.ts:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

platformBrowserDynamic().bootstrapModule(AppModule);

Здесь для нас важны две части:

  • platformBrowserDynamic() функция, вызывающая и возвращающая некий объект.
  • Этот объект используется для начальной загрузки нашего приложения.

Если мы слегка её перепишем, обнаружится одна интересная деталь:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { PlatformRef } from '@angular/core';


// Создать браузерную платформу
const platformRef: PlatformRef = platformBrowserDynamic();

// Начальная загрузка приложения
platformRef.bootstrapModule(AppModule);

platformBrowserDynamic —это фабрика платформ, функция, создающая новые экземпляры платформ. Результатом вызова функции platformBrowserDynamic является PlatformRef. PlatformRef — это простой сервис Angular, который умеет производить начальную загрузку наших приложений. Для лучшего понимания того, как этот экземпляр PlatformRef создаётся, давайте повнимательнее проследим за реализацией этой функции platformBrowserDynamic:

-2

Здесь мы можем видеть, что функция platformBrowserDynamic — это всего лишь результат функции createPlatformFactory, которая принимает следующие параметры:

  • Родительская фабрика платформ — platformCoreDynamic
  • Название для новой платформы — ‘browserDynamic’
  • Дополнительные провайдеры — INTERNAL_BROWSER_DYNAMIC_PLAFORM_PROVIDERS

Здесь platformCoreDynamic — это функция родительской фабрики платформ. Мы можем рассматривать platformCoreDynamic и platformBrowserDynamic как состоящие в иерархии наследования. Поэтому функция createPlatformFactory просто помогает нам получить из одной фабрики платформ другую. Всё просто.

Самое интересное происходит в этой иерархии наследования чуть дальше. На самом деле, platformCoreDynamic наследует platformCore, у которой, в свою очередь, нет родителя.

Так что полная иерархия для platformBrowserDynamic выглядит следующим образом:

-3

Однако фабрики платформ Angular не меняют поведения родительских фабрик платформ в процессе наследования. Они обеспечивают наши приложения дополнительными токенами и сервисами.

Кажется, немного сложновато. Попробуем разобраться с функцией createPlatformFactory и понять, как именно создаются фабрики платформ Angular.

Вот суперупрощённый алгоритм для createPlatformFactory:

-4

Когда мы вызываем эту функцию, она возвращает функцию фабрики платформ, которая принимает дополнительные StaticProviders для наших приложений. И если мы используем родительскую фабрику платформ, функция createPlatformFactory вызовет её и вернёт её значение или же просто создаст и вернёт новую платформу. Для лучшего понимания рассмотрим процесс создания platformBrowserDynamic шаг за шагом:

  • platformBrowserDynamic создаётся в результате вызова функции createPlatformFactory с platformCoreDynamic в качестве родительской платформы.
  •  Для создания новой платформы вызываем функцию platformBrowserDynamic.
  • Она проверяет, существует ли parentPlatformFactory, и вызывает её с помощью ряда дополнительных провайдеров, а затем просто возвращает её значение:

if (parentPlatformFactory) {
return parentPlatformFactory(injectedProviders);
}

4. На этом этапе можно заметить, что результатом функции platformBrowserDynamic на самом деле является результат функции platformCoreDynamic со всеми сервисами, используемыми platformBrowserDynamic.

5. platformCoreDynamic создаётся так же, как platformBrowserDynamic, но с двумя отличиями — она расширяет platformCore и использует собственные провайдеры.

export const platformCoreDynamic = createPlatformFactory(
platformCore,
'coreDynamic',
CORE_DYNAMIC_PROVIDERS,
);

Здесь мы можем заметить ту же ситуацию: из-за существования родительской платформы мы просто возвращаем результат фабрики родительской платформы с дополнительными провайдерами:

platformCore([ ...CORE_DYNAMIC_PROVIDERS, ...BROWSER_DYNAMIC_PROVIDERS ]);

6. Но внутри platformCore у нас несколько другая ситуация.

export const platformCore = createPlatformFactory(
null,
'core',
CORE_PLATFORM_PROVIDERS,
);

Здесь в CORE_PLATFORM_PROVIDERS содержится самый важный провайдер — сервис PlatformRef. Когда мы используем null в качестве родительской фабрики платформ, функция createPlatformFactory просто возвращает результат функции createPlatform.

7. Функция createPlatform, в свою очередь, будет просто извлекать PlatformRef из injector. И возвращать её к источнику вызова.

function createPlatform(injector: Injector): PlatformRef {
return injector.get(PlatformRef);
}

8. Теперь у нас есть PlatformRef:

const ref: PlatformRef = platformBrowserDynamic();

Обратите внимание: в процессе наследования платформы не меняют поведения PlatformRef явным образом. Вместо этого они дают новые наборы сервисов, которые использует PlatformRef в процессе начальной загрузки.

-5

Здесь можно заметить, что platformCore не похож на другие платформы. platformCore в каком-то роде особенный, потому как он отвечает за использование PlatformRef для процесса создания платформ и служит корневой платформой для всех платформ в экосистеме Angular.

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

  • PlatformRef —  сервис, который производит начальную загрузку приложения Angular.
  • Провайдеры —массив токенов и сервисов, используемых во время загрузки и запуска.

Как Angular-платформы делают возможным кроссплатформенный запуск

На этом этапе мы узнали, что такое Angular-платформы и как они создаются. Теперь обсудим, каким образом Angular-платформы делают из Angular кроссплатформенный фреймворк.

Всё дело в абстракции. Как известно, Angular в значительной степени основана на системе внедрения зависимостей. Именно поэтому довольно большая часть самой Angular представлена абстрактными сервисами:

  • Renderer2
  • Compiler
  • ElementSchemaRegistry
  • Sanitizer
  • и др.

Все эти сервисы и многие другие представлены абстрактными классами внутри Angular. Когда мы используем разные платформы, эти платформы обеспечивают соответствующие средства реализации для этих абстрактных классов. Например, здесь у нас ряд абстрактных сервисов в Angular. Лично я предпочитаю обозначать их синими кружочками:

-6

Но этим абстрактным классам не хватает реализации или функциональности. Когда мы используем браузерную платформу, она даёт собственные средства реализации для этих сервисов:

-7

Когда же мы используем, скажем, серверную платформу, она даёт уже свои собственные средства реализации этих абстрактных базовых сервисов:

-8

Теперь приведём конкретный пример.

Предположим, Angular использует абстракцию DomAdapter для обработки данных объектной модели документа DOM независимо от среды. Здесь имеет место упрощённая версия абстрактного класса DomAdapter.

-9

Когда мы используем браузерную платформу, она даёт соответствующие средства браузерной реализации для этого абстрактного класса:

export class BrowserDomAdapter extends DomAdapter { ... }

BrowserDomAdapter взаимодействует с браузерным DOM непосредственно, и поэтому не может быть использован где-то ещё, кроме браузера.

Вот почему для запуска на серверной стороне и в целях визуализации на стороне сервера мы используем серверную платформу, которая, в свою очередь, реализуется следующим образом:

export class DominoAdapter extends DomAdapter { ... }

DominAdapter не взаимодействует с DOM, так как у нас нет DOM на серверной стороне. Вместо этого он использует библиотеку domino, которая имитирует DOM для node.js.

В результате имеем следующую структуру:

-10

Заключение

Поздравляем! Вы добрались до конца статьи, в которой мы осветили ряд вопросов: что такое платформы Angular, как они создаются — а также прошли шаг за шагом процесс создания platformBrowserDynamic. И, наконец, разобрались, как концепция платформы делает из Angular кроссплатформенный фреймворк.

Читайте также:

Читайте нас в телеграмме и vk

Перевод статьи Nikita Poltoratsky: Angular Platforms in depth. Part 1. What are Angular Platforms?