Возможности Micro Frontend

Micro Frontend - это в первую очередь не техническая вещь

С моей точки зрения, Micro Frontend - это в первую очередь не техническая вещь. Основное преимущество Micro Frontend - это возможность организовывать небольшие команды вокруг программных модулей со сквозным характером. В лучшем случае эти модули выровнены с ограниченными контекстами.

В своей статье о микросервисах Мартин Фаулер и Джеймс Льюис заявили, что существует естественная корреляция между границами сервиса и контекста. Понятие ограниченного контекста происходит от Domain Driven Design (DDD). Стратегический дизайн DDD помогает разделить систему на более мелкие, менее зависимые части в соответствии с реальным процессом. Эти части называются ограниченными контекстами, и, согласно приведенному выше утверждению, они естественным образом коррелируют с микросервисами.

Сосредоточившись на аспекте модульности, единственное различие между микросервисами и Micro Frontend состоит в том, что последний включает интерфейс. Отсутствие внешнего интерфейса затрудняет создание команд со сквозной ответственностью и часто приводит к новому монолиту во внешнем интерфейсе.

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

На мой взгляд, этот аспект является основным преимуществом Micro Frontends, и с учетом сказанного я перенесу акцент на техническую часть этой статьи.

Федерация Micro Frontend сегодня

Чуть более двух лет назад мы начали видеть преимущества Micro Frontends в нашем бизнес-контексте. Вначале мы играли, создавая небольшие продукты из разных Micro Frontend. Наш первый подход к интеграции заключался в использовании i-фреймов, но в нашем контексте он казался громоздким, и мы особенно поразили его границы, когда мы интегрировали несколько Micro Frontend на одной странице, где каждому требовалось получить токен доступа oauth2 с использованием активного входа в систему. сеанс (oauth2 рекомендует не разрешать загрузку страницы входа в i-frame). Конечно, были бы варианты решения этой проблемы (например, использование потока кода аутентификации oauth2 с pkce для передачи долгоживущих токенов в i-кадры), но к тому времени мы уже заметили новый стандарт веб-компонентов. , который более интуитивно решает задачу интеграции.

Вначале мы создавали веб-компоненты по-разному. Мы экспортировали компоненты Vue.js как веб-компоненты или использовали менее сложные фреймворки, такие как stencil.js или полимер. Сегодня мы в основном создаем веб-компоненты, используя световой элемент с машинописным текстом и настраиваемую конфигурацию Webpack.

В нашем реальном приложении мы уже интегрируем довольно много Micro Frontend из разных доменов. Хотя интеграция веб-компонентов является нашим предпочтительным подходом, практика научила нас быть более гибкими и позволить все, что лучше всего подходит для команд, интегрирующих свои интерфейсы.

Тот факт, что нет библиотеки пользовательского интерфейса веб-компонентов, реализующей наш фирменный стиль / дизайн, или, по крайней мере, значительного количества веб-компонентов материального дизайна, на самом деле является причиной для многих команд, которые все еще избегают веб-компонентов. Им проще использовать одностраничную структуру приложения ‹you-name-it›, для которой существует такая библиотека компонентов пользовательского интерфейса. Однако недостатком этого подхода является то, что команда теряет возможность интеграции в качестве веб-компонента. Вы пробовали интегрировать сложный компонент Vue с приложением React? Даже если вы сможете преобразовать компонент в веб-компонент, это покажется неправильным. Это то, что я имею в виду под потерей возможности интеграции в качестве веб-компонента. (Между прочим. С моей точки зрения, наиболее перспективным проектом для решения проблемы отсутствия веб-компонентов материального дизайна на данный момент является материал-компоненты-веб-компоненты)

Наше контейнерное приложение, объединяющее все эти интерфейсы, построено с использованием Vue.js, и поэтому у нас есть Micro Frontend, интегрируемые в виде библиотек компонентов Vue, i-frame, веб-компонентов и путем добавления ссылки (если такой упрощенный подход применим).

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

Сосредоточение внимания на веб-компонентах сценарий интеграции довольно интуитивно понятен, но все же существуют недостатки, которые необходимо преодолеть. Одним из важных примеров является обработка зависимостей. Представьте, что есть контейнер приложения A и веб-компонент Micro Frontend B, который будет интегрирован с A. Кроме того, существует еще один веб-компонент C, используемый A и B. Чтобы быть более конкретным, предположим, что C - это простой компонент кнопки, B - это веб-компонент, который часто загружает изображения и позволяет ставить лайки с помощью кнопки C . A может быть приложением Vue.js, которое использует C в качестве кнопки входа и интегрирует B, чтобы запрашивать у пользователей лайки об изображениях. При интеграции A с B возникают проблемы, касающиеся C. Если A и B используют одну и ту же версию C, ее следует загрузить только один раз. В связи с этим необходимо убедиться, что custom-element из C определяется только один раз. В случае использования разных версий C необходимо избегать возможных конфликтов версий. Если A перестанет использовать C, это не повлияет на B во время выполнения.

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

К счастью, уже существуют решения для этой проблемы. Среди прочего, федерация модулей Webpack 5 является одной из них.

Федерация Micro Frontend завтра

использование интеграции модулей Webpack 5

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

Пример веб-компонента (удаленный)

Чтобы продемонстрировать его возможности, я реализовал простой нативный веб-компонент (без светового элемента, чтобы он был еще проще). Цель этого примера веб-компонента - загрузить новое случайное изображение с https://picsum.photos/. Частоту обновления в миллисекундах и длину квадратичного изображения можно определить с помощью custom-element:

<random-pic update-freq-ms="15000" image-length-px="300"></random-pic>

Вот как это может выглядеть:

чтобы увидеть компонент в действии, перейдите по ссылке: https://josros.gitlab.io/random-pic-component/

Цель состоит в том, чтобы предоставить компонент как удаленный модуль. « Удаленные модули - это модули, которые не являются частью текущей сборки и загружаются из так называемого контейнера во время выполнения ».

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

// install Webpack 5 (beta version, v.20 is used in this example)
npm i [email protected] -D

Добавьте конфигурацию объединения модулей в файл webpack.config.js. Ключевая часть:

randomPic - имя модуля. Модуль предоставляет образец компонента под именем ./component, которое относится к фактической реализации веб-компонента.

Учитывая полный webpack.config.js, выполнение сборки Webpack

webpack --mode production

переносит компонент с помощью babel и создает файл randomPicEntry.js, используемый в качестве точки входа для загрузки компонента из другого места, что будет продемонстрировано в следующем разделе. (Если вы посмотрите на фактический файл webpack.config.js, просто проигнорируйте пока разделяемую часть.)

Вместе с демонстрационной страницей компонента проект примера компонента развертывает файлы, созданные с помощью Webpack, на страницах gitlab с помощью простого файла gitlab-ci.yml.

Если вас интересует способ настройки этого примера с помощью машинописного текста, посмотрите: https://gitlab.com/josros/random-pic-component-ts

Компонентная интеграция (хост)

Аналог пульта ДУ - простой проект Webpack, который интегрирует компонент random-pic с использованием объединения модулей. В дальнейшем я буду называть этот компонент «хостом».

Для загрузки пульта в наш хост-проект необходимы следующие вещи:

Во-первых, основной проект также должен использовать Webpack 5:

// install Webpack 5 (beta version, v.20 is used in this example)
npm i [email protected] -D

В своем файле index.html ему необходимо импортировать скрипт точки входа пульта ДУ:

<script src="https://josros.gitlab.io/random-pic-component/randomPicEntry.js"></script>

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

после загрузки модуля создается custom-element, который добавляется в DOM.

Чтобы сообщить Webpack, как разрешить удаленный модуль (randomPic / component), файлу webpack.config.js также нужна некоторая дополнительная информация в основном проекте:

Имя модуля в этом проекте - интеграция, а конфигурация для пультов указывает Webpack разрешить randomPic как удаленный модуль.

Все остальные части не отличаются от стандартной конфигурации в Webpack ‹5. Полный файл webpack.config.js определяет, что ./src/index.js переносится в main.js с помощью загрузчика babel, о котором я упоминаю в файле index.html:

<script type=”module” src=”main.js”></script>

Если вы перейдете по адресу: https://josros.gitlab.io/random-pic-component-integration/, вы увидите удаленный компонент, отображаемый как часть основного проекта, в который компонент загружается с использованием федерации модулей Webpack 5.

Теперь, когда мы рассмотрели базовый сценарий интеграции с использованием объединения модулей Webpack 5, в следующем разделе будет показано, как объединение модулей обрабатывает общие модули.

Общие модули

Как вы могли заметить, над изображением в удаленном компоненте есть кнопка нравится. Такие же кнопки вы можете найти в основном проекте (как приложение).

Кнопка является частью проекта material-components-web-components и используется как зависимость в нашем удаленном компоненте, а также в основном проекте:

Поскольку мы не хотим, чтобы зависимость загружалась несколько раз, мы даем указание Webpack 5 разрешить эту зависимость за нас.

Для этого в файле проекта удаленного компонента webpack.config.js необходимо определить mwc-button как общий модуль, настроив конфигурацию ModuleFederationPlugin следующим образом:

По сравнению с версией, показанной ранее, здесь был добавлен общий объект. Определение сообщает Webpack, что mwc-button может использоваться всеми модулями. Однако для этого требуется определенная версия, которая в данном случае определена в файле package.json. Для получения дополнительной информации о том, как настроить общие объекты, вы можете прочитать эту статью.

mwc-button также должна быть определена как общий модуль в основном проекте. Вот как там настраивается конфиг ModuleFederationPlugin:

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

localhost: 3013 - это место, где работает хост. index.html загружается первым. Далее идет файл randomPicEntry.js из нашего удаленного компонента на localhost: 3003. После этого загружается файл main.js, который, по сути, является пакетом хост-приложения. Оттуда mwc-button разрешается. Он исходит от localhost: 3013, потому что он используется в обеих частях.

axios, не является разделяемым модулем и используется только как зависимость внутри удаленного компонента, поэтому загружается оттуда. Наконец, комплект удаленных компонентов извлекается с localhost: 3003.

Ключевым моментом является то, что mwc-button загружается только один раз, даже если она используется в удаленном компоненте, а также в основном проекте.

Резюме

На момент написания этой статьи Webpack 5 все еще находится в стадии бета-тестирования, но, как пытается показать эта статья, он может преодолеть некоторые недостатки, которые в настоящее время существуют с интеграцией Micro Frontend.

Помимо преимущества, объединение модулей Webpack 5 обеспечивает масштабируемое решение интеграции кода приложения во время выполнения, оно решает проблему совместного использования зависимостей гибким способом. Если зависимость используется в нескольких модулях объединенного приложения, она автоматически использует самый высокий доступный пакет. При этом он учитывает многочисленные ограничения, настраиваемые для общей зависимости. В качестве запасного варианта он принимает зависимость, предоставляемую самим удаленным модулем. Это особенно полезно, поскольку во время выполнения условия могут измениться.

Создание портала для нескольких доменов, а также интеграция устаревших приложений, объединение модулей Webpack 5 не поможет нам во всех наших сценариях интеграции. Там, где i-frame были выбраны по уважительным причинам, проблемы с их интеграцией останутся. Но не меньше, чем наш предпочтительный подход к интеграции собственных веб-компонентов, Webpack 5 обещает стать эволюцией.

Сделав один шаг назад, чтобы добиться успеха с Micro Frontends или даже с разработкой программного обеспечения в целом, недостаточно выбрать правильный инструмент. Более того, важно привести команды в соответствие с рамками контекста и возложить на них сквозные обязанности. Последнее позволяет им напрямую оценивать и удовлетворять потребности клиентов, вместо того, чтобы увлекаться техническими мечтами. Тем не менее я убежден, что рассматривать команды как стратегические, а не подразделения, обеспечивающие доставку, гораздо важнее, чем наличие лучших технологий. По этой причине основным преимуществом Micro Frontend является то, что он напрямую поддерживает эту цель.