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

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

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

  • Введение
  • Путешествие в Мирко-Фронтенды
  • Преимущества Mirco-Frontends
  • Функции Mirco-Frontends
  • Как мы разделяем приложения
  • Различные подходы к микроинтерфейсам
  • Микро-интерфейсные платформы
  • Пример проекта микроинтерфейса с Angular
  • Сводка
  • Заключение

Введение

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

Обычно проекты бывают разных размеров и с разными требованиями. Если ваш проект достаточно прост, чтобы иметь две или три страницы и может поддерживаться одной командой, вам не нужно думать об этих микро-интерфейсах. Вы можете просто реализовать любой из выбранных вами фреймворков, таких как Angular, React или Vuejs.

Но это не всегда так. Иногда ваше фронтенд-приложение может быть небольшой частью другого большого приложения, или ваше приложение состоит из множества разделов и функций, которые разрабатываются разными командами, или ваше приложение выпускается в производство, функция за функцией, разработанная отдельными командами. Если вы находитесь в одной из таких ситуаций, вам нужно подумать о Micro Frontends. Давайте посмотрим на это на диаграмме ниже.

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

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

Преимущества микроинтерфейсов. Вот преимущества этой архитектуры.

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

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

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

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

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

Разработка приложений становится быстрее. Вся разработка становится быстрее и проще благодаря отдельным командам.

CI/CD становится проще. Каждое приложение можно интегрировать и развертывать отдельно, что значительно упрощает процесс CI/CD. Когда мы исправляем приложение или внедряем новую функцию, нам не нужно беспокоиться обо всем приложении, поскольку все функции независимы.

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

Отсутствие общего кода.В больших приложениях мы, как правило, используем общий код для разных функций, но это плохо масштабируется и приводит к множеству ошибок и взаимозависимостей по мере того, как приложение становится все больше и больше. Это не относится к микрофронтендам, поскольку мы не делимся кодом, если только он не является тупым компонентом.

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

Особенности Мирко-Фронтендов

  • Каждый интерфейс представляет определенную функцию или поддомен всего приложения.
  • Каждый интерфейс может быть реализован отдельной командой.
  • Каждый интерфейс может быть реализован с использованием различных технологий.
  • Они не могут разделять логику и ее независимость друг от друга.
  • Каждый Frontend может принадлежать одной команде.

Как мы разделяем приложения

Давайте посмотрим, как мы можем разделить большие приложения на микрофронтенды. Нет никаких конкретных критериев для разделения приложений, и мы можем разделить их несколькими способами в зависимости от наших потребностей. Мы увидим все возможные способы разделения приложений.

По функциям

Это наиболее распространенный метод, поскольку мы можем легко разделить функции приложения. Например, если есть три функции для панели инструментов приложения, профиля и представлений, мы можем сделать каждую функцию отдельным приложением и подключать и отключать в DOM с помощью Launch.js. Этот Launch.js может быть отдельным приложением или просто простым приложением JavaScript.

По разделам

Некоторые приложения имеют так много функций в каждом разделе, например, coinbase, Gmail и т. д. Мы можем реализовать каждый раздел как новое приложение в этом сценарии.

По страницам

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

По домену

Разделение приложения на основе домена также является одним из наиболее распространенных подходов.

Различные подходы к микро-фронтендам

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

  • Интерфейсы
  • Через NGINX
  • Веб-компоненты/элементы Angular
  • Библиотеки Angular
  • Монорепозитории
  • Индивидуальный оркестратор

Фреймворки микро-интерфейса

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

одноместный спа

single-spa — это фреймворк javascript для интерфейсных микросервисов, который может быть реализован со всеми тремя популярными фреймворками/библиотеками, такими как Angular, React и Vue.js. Он может лениво загружать приложения в зависимости от необходимости, и вы можете посетить их веб-сайт для получения дополнительной информации.

фринт.js

frint.js — это модульная среда JavaScript для создания масштабируемых и реактивных приложений. Он еще не поддерживает Angular, но поддерживает React. Если вы создаете реактивное приложение с нуля и только начинаете, этот фреймворк для вас. Вы можете проверить их веб-сайт для получения дополнительной информации.

Пример проекта микро-фронтенда с Angular

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

Мы разделим это приложение по разделам, как показано на диаграмме ниже. Всего мы собираемся реализовать 4 приложения: HeaderApp, DashboardApp, FooterApp и корневое приложение.

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

// root app runs on port 4200
git clone https://github.com/ahmedbhl/micro-root.git
npm install
npm start

// micro header runs on port 4300
git clone https://github.com/ahmedbhl/micro-header.git
npm install
npm start

// micro dashboard runs on port 4202
git clone https://github.com/ahmedbhl/micro-dashboard.git
npm install
npm start

// micro footer runs on port 4201
git clone https://github.com/ahmedbhl/micro-footer.git
npm install
npm start

Вы можете получить доступ ко всему приложению наhttp://localhost:4200/

Вот HTML-файл индекса микрокорневого приложения. Мы импортируем все три приложения в строке 10 и регистрируем приложения с соответствующим именем и местоположением. Поскольку мы загружаем все приложения при загрузке страницы, мы не определяем какие-либо конкретные пути контекста.

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Security-Policy" content="default-src *  data: blob: 'unsafe-inline' 'unsafe-eval'; script-src * 'unsafe-inline' 'unsafe-eval'; connect-src * 'unsafe-inline'; img-src * data: blob: 'unsafe-inline'; frame-src *; style-src * data: blob: 'unsafe-inline'; font-src * data: blob: 'unsafe-inline';">
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Your application</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="importmap-type" content="systemjs-importmap">
    <script type="systemjs-importmap">
      {
        "imports": {
          "footer": "http://localhost:4201/main.js",
          "dashboard": "http://localhost:4202/main.js",
          "header": "http://localhost:4300/main.js",
          "single-spa": "https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.5/system/single-spa.min.js"
        }
      }
    </script>
    <link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/single-spa/4.3.5/system/single-spa.min.js" as="script" crossorigin="anonymous" />
    <script src='https://unpkg.com/[email protected]/minified.js'></script>
    <script src="https://unpkg.com/zone.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/import-map-overrides.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/4.0.0/system.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/4.0.0/extras/amd.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/4.0.0/extras/named-exports.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/4.0.0/extras/named-register.min.js"></script>
    <style>
    </style>
  </head>
  <body>
    <script>
      System.import('single-spa').then(function (singleSpa) {
        singleSpa.registerApplication(
          'header',
          function () {
            return System.import('header');
          },
          function (location) {
            return true;
          }
        )

        singleSpa.registerApplication(
          'dashboard',
          function () {
            return System.import('dashboard');
          },
          function (location) {
            // return location.pathname.startsWith('/app2');
            return true;
          }
        )

        singleSpa.registerApplication(
          'footer',
          function () {
            return System.import('footer');
          },
          function (location) {
            // return location.pathname.startsWith('/app1');
            return true;
          }
        );
        
        singleSpa.start();
      })
    </script>
    <import-map-overrides-full></import-map-overrides-full>
  </body>
</html>

корневой файл index.html

Вы можете указать путь к местоположению /header, чтобы заголовок загружался, когда URL-адрес браузера переходит к /header. Давайте проверим это.

<script>
      System.import('single-spa').then(function (singleSpa) {
        singleSpa.registerApplication(
          'header',
          function () {
            return System.import('header');
          },
          function (location) {
            return location.pathname.startsWith('/header');
            // return true;
          }
        )

с заголовком /header

Заключение

Я знаю, что микрофронтенды — это такая модная вещь, но вы не должны использовать их для каждого приложения. Не используйте его, если ваше приложение маленькое и не усложняйте его. Этот подход должен сделать весь наш процесс плавным, а не слишком сложным. Так что подумайте, прежде чем использовать этот подход.

Спасибо за чтение и продолжайте посещать!