По мере роста внешнего мира, архитектурные решения для него также должны расти. Основная идея микро-интерфейсов состоит в том, чтобы разделить интерфейсы на независимые части, чтобы независимые команды могли их поддерживать.
«Архитектурный стиль, в котором независимо доставляемые веб-приложения объединены в единое целое»
Преимущества микросервисов
- Разъединенная кодовая база.
- Автономные команды.
- Технология и рамки агностик.
- Независимые развертывания.
- Масштабируемость.
- Повторное использование.
Микро-Фронтэнды
Микро-интерфейсы имеют те же преимущества, что и микро-сервисы, только с бэкэндами. Команды просто становятся сквозными.
Поскольку вы можете использовать разные фреймворки и технологии, это не значит, что вы должны это делать.
Когда использовать микро-интерфейсы
- Огромная база кода, которой способствуют разные команды.
- Право собственности на код становится грязным.
- Развертывание задерживается из-за других частей приложения.
- Вы хотите использовать разные рамки FE.
оркестровка
С помощью оркестровки мы можем объединить разные микро-интерфейсы в одно работающее приложение. Это можно сделать как на сервере, так и на стороне клиента. Для максимальной производительности мы должны объединить эти подходы.
Для этого есть еще одно решение, называемое интеграцией времени сборки .
Интеграция времени сборки
- Каждое приложение микро-интерфейса представляет собой пакет npm.
- Основное приложение (оркестратор / контейнер) встраивается в окончательный комплект со всеми зависимостями (микро-интерфейсами).
JavaScript
xxxxxxxxxx
1
{
2
"name" : "@ super-app / container" ,
3
"версия" : "1.0.0" ,
4
"description" : "Мое супер приложение" ,
5
"зависимости" : {
6
"@ super-app / products-list" : "2.0.0" ,
7
"@ super-app / header" : "4.5.2" ,
8
"@ super-app / order" : "1.0.0"
9
}
10
}
Кажется, это имеет смысл, но это не рекомендуется, потому что у него есть один большой недостаток. Каждый раз, когда изменяется одно из приложений микро-интерфейса, весь оркестратор со всеми его зависимостями должен перестраивать и создавать новый выпуск. Это может вызвать задержки, откаты или ошибки для каждого микро-интерфейса, и это то, что мы хотели бы избежать. Кроме того, у каждой команды должны быть зависимости от одних и тех же версий пакетов, что может значительно усложнить создание новых версий.
1. Клиентская оркестровка
- Клиентская маршрутизация.
- разделение государства.
- Зарегистрируйте все приложения.
- Разрешить общие зависимости, если таковые имеются.
- Инициализируйте основное приложение.
- Создавайте фрагменты из разных приложений микро-интерфейса.
Вы можете дополнить этот список различными библиотеками, такими как:
- single-spa https://single-spa.js.org/ (маршрутизатор верхнего уровня).
- hinclude http://mnot.github.io/hinclude/ (включает фрагменты HTML).
- h-include https://github.com/gustafnk/h-include (включает фрагменты HTML с использованием веб-компонентов).
Композиция фрагментов может быть выполнена с помощью простого вызова Ajax для различных API, которые могут возвращать предварительно отрендеренный HTML, который может быть гидратирован во внешнем интерфейсе, или только возвращает необходимый тег сценария и определенный тег HTML с идентификатором, с помощью которого может отображаться загруженный фрагмент. сам.
Кроме того, есть возможность реализовать оркестровку самостоятельно, используя vanilla JS или другой фреймворк.
1.1 Маршрутизация
- Используйте History API для инициализации встроенных маршрутизаторов.
- Пользовательские события браузера или библиотека PubSub .
- Оставьте маршрутизацию в приложении Orchestrator.
1.2 Совместное использование глобального состояния и связь между приложениями
- В этом случае полезен шаблон Observables с экспортированным открытым состоянием каждого микро-интерфейса — RxJS .
- Пользовательские события браузера .
- Файлы cookie, сеанс или локальное хранилище.
1.3 Общий код — в основном библиотека пользовательского интерфейса
- При выборе сторонней библиотеки вы должны выбрать ту, которая поддерживает все используемые фреймворки в ваших микро-интерфейсах.
- В случае, если вы разрабатываете свою собственную библиотеку, вы можете использовать веб-компоненты, чтобы сделать их универсальными.
- Ответственность за разработку и поддержание этой библиотеки должна быть на каждой команде. Не создавайте конкретную команду для этой цели
1.4 Столкновение стилей
- Определите конкретный префикс для классов CSS для каждой команды.
- Используйте стиль БЭМ .
- Используйте библиотеки CSS и JS, которые помогут вам избежать коллизий — JSS , styled-компоненты и т. Д.
- Shadow DOM от веб-компонентов .
1.5 SEO и UX
- Skeleton UI — предустановленный экран-заставка для еще не загруженного контента.
- Рендеринг на стороне сервера с помощью ESI или SSI (описан в оркестровке на стороне сервера).
1.6 Веб-компоненты на помощь
Они определены 4 спецификациями:
1.6.1 Пользовательские элементы
Пользовательский элемент API позволяет создавать полнофункциональные, пользовательские HTML элементы с помощью методов жизненного цикла, обработчики изменения атрибутов, обработчиков событий и т.д.
Процесс создания пользовательского элемента:
- Создайте класс, который расширяет
HTMLElement
класс. - Определите методы своего жизненного цикла, пользовательские свойства и т. Д.
- Свяжите новый элемент с шаблоном HTML (внутри
connectedCallback()
метода жизненного цикла). - Зарегистрируйте этот элемент с помощью API пользовательских элементов .
- Используйте этот элемент в своем HTML.
JavaScript
xxxxxxxxxx
1
класс MyIcon расширяет HTMLElement {
2
constructor () {
3
супер ();
4
это . _iconCode = null ;
5
}
6
7
статические получить наблюдаемые атрибуты () {
8
return [ "code" ];
9
}
10
11
attributeChangedCallback ( name , oldValue , newValue ) {
12
// имя всегда будет "кодом" из-за наблюдаемых атрибутов
13
это . _iconCode = newValue ;
14
это . _render ();
15
}
16
connectedCallback () {
17
это . _render ();
18
}
19
20
получить код () {
21
верни это . _iconCode ;
22
}
23
24
установить код ( значение ) {
25
это . setAttribute ( «код» , значение );
26
}
27
28
_render () {
29
// добавляем необходимые элементы в DOM или теневой DOM
30
}
31
}
32
33
customElements . define ( «my-icon» , MyIcon );
34
35
// Использование: <my-icon code = "flower"> </ my-icon>
1.6.2 Shadow DOM
- https://w3c.github.io/webcomponents/spec/shadow/ .
- https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM .
JavaScript
xxxxxxxxxx
1
Элемент . attachShadow ();
attachShadow
Метод принимает только один параметр, который является объектом с одним свойством, mode
. Он позволяет вам создавать изолированные DOM-деревья (стили с областями видимости, автономные компоненты) с двумя режимами open
и closed
.
Open
означает, что вы можете получить доступ к теневой DOM, используя JavaScript, написанный в контексте главной страницы. С другой стороны, closed
означает, что к теневой DOM можно получить доступ только с помощью Javascript из контекста пользовательских элементов. Это действительно полезно, когда вам нужно изолировать свой CSS.
JavaScript
xxxxxxxxxx
1
импорт React из 'реакции' ;
2
импортировать ReactDOM из ' response -dom' ;
3
4
импортировать приложение из ./App ' ;
5
6
класс MyCusotomElement расширяет HTMLElement {
7
constructor () {
8
супер ();
9
это . тень = это . attachShadow ({ mode : 'closed' }); // Или открыть
10
}
11
12
connectedCallback () {
13
ReactDOM . render ( < App /> , this . shadow );
14
}
15
}
16
17
customElements . define ( "my-custom-element" , MyCusotomElement );
1.6.3 ES-модули
- https://html.spec.whatwg.org/multipage/webappapis.html#integration-with-the-javascript-module-system .
Импорт / экспорт модулей JS, больше ничего.
1.6.4. HTML-шаблоны
- https://html.spec.whatwg.org/multipage/scripting.html#the-template-element/ .
- https://html.spec.whatwg.org/multipage/scripting.html#the-slot-element .
С помощью HTML-шаблонов ( <template>
) вы можете создавать HTML-фрагменты, которые не отображаются во время загрузки, но вы можете инициализировать их во время выполнения с помощью JavaScript.
HTML
xxxxxxxxxx
1
< div id = "example" > </ div >
2
3
< template id = "example-template" >
4
< таблица >
5
< tr >
6
< td > Что это? </ td >
7
< td > Мой пример шаблона. </ td >
8
</ tr >
9
</ table >
10
</ template >
JavaScript
xxxxxxxxxx
1
// Найти наш шаблон
2
var template = документ . querySelector ( '# example-template' );
3
4
// Находим наш целевой элемент
5
var target = document . querySelector ( '#example' );
6
7
// Клонируем содержимое нашего шаблона
8
var content = document . importNode ( шаблон . контент , правда );
9
10
// Добавляем содержимое шаблона к нашему целевому элементу
11
цель . appendChild ( content );
Еще один полезный элемент <slot>
. Он является частью технологии веб-компонентов и используется в качестве заполнителя внутри веб-компонента, который можно заполнить собственной разметкой.
HTML
xxxxxxxxxx
1
< template id = "example-template" >
2
< div class = "attribute" >
3
< h4 > < span > Атрибуты </ span > </ h4 >
4
< slot name = "attribute" > < p > Нет </ p > </ slot >
5
</ div >
6
</ template >
7
8
< element-attribute >
9
< span slot = "attribute" > Атрибуты из веб-компонента. </ span >
10
</ element-attribute >
JavaScript
xxxxxxxxxx
1
customElements . определить ( 'атрибуты элемента' ,
2
класс расширяет HTMLElement {
3
constructor () {
4
супер ();
5
шаблон const = документ
6
, getElementById ( 'пример-шаблон' )
7
, содержание ;
8
9
это . attachShadow ({ mode : 'open' })
10
, appendChild ( template . cloneNode ( true ));
11
}
12
}
Результат:
Определенный элемент span с атрибутом slot отображается в элементе slot с атрибутом, name
значение которого совпадает со значением slot
атрибута в нашем элементе span .
2. Серверная оркестровка
- Маршрутизация сервера с прокси-запросами.
- Зарегистрируйте все приложения.
- Разрешить общие зависимости, если таковые имеются.
- Обслуживание и составление фрагментов из разных приложений на основе микро-интерфейса.
2.2. Приложение начальной загрузки
Мы можем назвать решение для оркестрации на стороне сервера приложением Bootstrap. Это может быть сделано по-разному, и, как правило, оно более сложное и состоит из более чем одного решения. Я собираюсь описать, как некоторые крупные компании делают это.
2.2.1 Решение Zalandos
Он называется Project Mosaic9 https://www.mosaic9.org/ .
Вариант использования прост, как вы можете видеть на картинке. Пользователь заходит на страницу, и браузер подключается к маршрутизатору, который решает, является ли это вызовом API или вызовом макета. В случае вызова API маршрутизатор передает запрос на нужный API. В случае вызова уровня маршрутизатор вызывает службу Layout, которая знает обо всех возможных схемах размещения и загружает их с разных конечных точек.
Как вы можете видеть на следующем рисунке, они создали проекты с открытым исходным кодом для выполнения всех описанных шагов.
2.2.2 Решение Facebook
Они называют это BigPipe. Это похоже на Tailor.js из решения Zalandos. На самом деле, Tailor.js был вдохновлен BigPipe Facebook. Оригинальный пост, где вы можете прочитать о том, как это работает, находится здесь: https://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919/ .
2.3 Возможности композиции фрагмента
Теперь поговорим о технической стороне композиции фрагментов на стороне сервера. Существуют две старые технологии, с помощью которых мы можем легко выполнить композицию ( серверная часть включает (SSI) и пограничная сторона включает ( ESI) ). Они используются для объединения разных HTML-разметок в одну. В обоих случаях нам нужно поддерживать карту URL-адресов, соответствующих статическим HTML-файлам.
2.3.1 Включение на стороне сервера (SSI)
- http://www.alticore.eu/wasd_root/doc/env/env_0400.html .
- https://www.owasp.org/index.php/Server-Side_Includes_(SSI)_Injection .
- https://www.w3.org/Jigsaw/Doc/User/SSI.html .
- http://httpd.apache.org/docs/current/howto/ssi.html#basic .
- простой интерпретируемый серверный язык сценариев.
- поддерживается Apache, Nginx и т. д.
В основном файле HTML:
HTML
xxxxxxxxxx
1
< html lang = "en" >
2
< голова >
3
< meta charset = "utf-8" >
4
< title > SSI </ title >
5
</ head >
6
< тело >
7
<! - # include file = "$ PAGE.html" ->
8
</ body >
9
</ html >
Внутри конфига Nginx:
Джава
xxxxxxxxxx
1
сервер {
2
слушать 8080 ;
3
имя_сервера localhost ;
4
5
root / usr / share / nginx / html ;
6
индекс индекс . HTML ;
7
8
# Включите на в SSI ferature
9
ssi on ;
10
11
# Установите в $ PAGE переменная используется внутри в основной HTML
12
местоположение / просмотр {
13
установить $ PAGE 'browse' ;
14
}
15
16
местоположение / профиль {
17
установить $ PAGE 'профиль'
18
}
19
}
2.3.2 Крайняя сторона включает (ESI)
- https://www.w3.org/TR/esi-lang .
- Небольшой язык разметки.
- Это всего лишь предложение и не является стандартом.
- Поддерживается различными технологиями или библиотеками (Nginx, Varnish и т. Д.).
- Для NodeJS есть пакет nodei npm.
HTML
xxxxxxxxxx
1
< html lang = "en" >
2
< голова >
3
< meta charset = "utf-8" >
4
< title > ESI </ title >
5
</ head >
6
< тело >
7
< esi: include src = "http://example.com/1.html" alt = "http://example.com/2.html" />
8
</ body >
9
</ html >
2.3.3 Собственная реализация
Вы можете реализовать свой собственный анализатор или какой-либо помощник по тегам на стороне сервера. Почти каждая библиотека шаблонов имеет некоторые возможности для реализации разрешения пользовательских тегов.
Заключение
Выберите свой инструмент, проанализировав проблему. Не пытайтесь решить все проблемы с вашим любимым инструментом. Если вы выберете архитектуру микро-интерфейса, вы можете выбрать две группы:
Полная независимость
- Каждая команда выбирает свой технический стек — без совместного использования кода.
- Каждый фрагмент делает свои собственные вызовы API .
- Каждый вид состоит из полностью функциональных фрагментов .
- Каждое приложение микро-интерфейса имеет свой собственный CI / CD .
Стратегическое Сотрудничество
- Согласуйте технический стек и поделитесь общими библиотеками.
- Вызовы API проходят через приложение начальной загрузки .
- Библиотека общего интерфейса .
- Общий CI / CD .