Вокруг микрофронтендов было много разговоров и шумихи.

С https://micro-frontends.org/ системы Microfrontend

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

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

Простая иллюстрация, объясняющая эту идею, показана ниже:

Микросервисы с интерфейсом Monolith

Микросервисы с Micro Frontend

Микрофронтенды приносят такие же преимущества, как производительность, инкрементальные обновления, несвязанные кодовые базы, независимые развертывания, автономные команды для фронтенд-инжиниринга, как микросервисы привносят в бэкэнд-сервисы.

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

Уже есть несколько архитектур, которые используются и предлагаются для достижения архитектуры микрофронтенда. В посте Кэма Джексона о Мартине Фаулере есть несколько хороших подходов.

Давайте посмотрим, как наше отношение к микрофронтендам в Cloudfactory влияет на организацию страниц.

Микрофронтенды в действии

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

Мы видели подобную организацию в интерфейсе консоли AWS и некоторых интерфейсах Facebook.

Альтернативная реализация для создания большого единого SPA через интеграцию во время выполнения с помощью JavaScript задокументирована и прекрасно реализована на https://microfrontends.com/ и https://martinfowler.com/articles/micro-frontends.html. #Время выполненияIntegrationViaJavascript»

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

Решение использует React с Typescript и Webpack с набором модулей ESNext. Эта комбинация позволяет нам создавать чрезвычайно оптимизированные несколько приложений без увеличения размера пакета и использовать все преимущества разделения кода и ленивой загрузки.

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

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

Концептуальная идея

Идея высокого уровня состоит в том, чтобы экспортировать компоненты в виде модулей ESNext, которые можно легко повторно использовать через интерфейсы через CDN и лениво загружать, когда это применимо. Этот тип интеграции не нов, и мы видели это со времен плагинов и виджетов jQuery.

Для любых общих компонентов и интерфейсов мы создаем модули узла и с конфигурацией машинописного текста module, установленной в esnext, и с правильно установленной конфигурацией веб-пакета output.library, мы получаем модули для работы во время выполнения, загружаемого через CDN. Когда для параметра publicPath веб-пакета задан путь CDN, выплескивание кода и ленивый/задумчивый React работают хорошо. Нам нужно только знать основную точку входа основного файла модуля, которую можно сделать предсказуемой, если следовать стандартному общекорпоративному соглашению.

Образец tsconfig

{
    "compilerOptions": {
      "lib": ["dom", "es2015", "es2016"],
      "module": "esnext",
      "moduleResolution": "node",
      "target": "es5",
      "jsx": "react",
      ...
    }
  }

Пример конфигурации веб-пакета

const version = `${require('./package.json').version}`;
  //...
  module.exports = {
    entry: [
      // ...
    ],
    output: {
      filename: 'main.js',
      path: path.resolve(__dirname, 'dist', version),
      library: ['MFE', 'SHC'],
      publicPath: `https://cdn/path/shared-components/dist/${version}/`,
      // ...
    },
  // ...
  }

Мы получаем экспортированные модули в глобальном MFE.SHC объекте, и с правильным набором publicPath с динамически вычисляемым version это упрощает создание версионированных артефактов.

Мы придерживаемся семантического управления версиями, поэтому игнорируем версии патчей, поэтому 1.2.1, 1.2.2 .. 1.2.9 объединяются в 1.2.x. Это также дает нам возможность вносить изменения в интерфейс без необходимости повторного развертывания определенных страниц. Мы также можем игнорировать младшую версию и всегда использовать 1.x.x, последнюю основную версию. Это позволит, как показано в примере в демонстрации, команде C публиковать обновление своего интерфейса с любым действием команды A, которая управляет страницей, если они обновляют основную версию.

Затем мы используем веб-пакеты externals для поиска модулей во время выполнения.

module.exports = {
    // ...
    externals: {
      "react": "MFE.GLB.React",
      "react-dom": "MFE.GLB.ReactDOM",
      "shared-components": "MFE.SHC"
    },
    // ...
  }

У нас есть глобальные зависимости, экспортированные в один пакет, доступ к которому можно получить по адресу MFE.GLB.

Упрощенная рабочая демонстрация доступна по адресу https://rohitrox.github.io/microfrontend-esnext-demo/team-a-page/dist/.

Теперь реализация может быть улучшена для поддержки интеграции javascript с микроинтерфейсами во время выполнения. Учитывая развивающееся приложение в cloudfactory, мы чувствовали, что еще не готовы позволить всем микроинтерфейсам автоматически обновляться. Контейнерное приложение/страница и микрофронтенды постоянно меняются, поэтому лучше всего было следить за автоматическими обновлениями на основе основных версий. Если в микроинтерфейсе есть выпуск основной версии, приложение-контейнер должно подтвердить и опубликовать новую версию самого себя, которая будет использовать обновленный микроинтерфейс.

Далее для связи между компонентами микрофронтенда мы используем React props и Custom Events. Существует также ряд доступных библиотек шины событий с открытым исходным кодом.

Для демонстрации я использовал GitHub для всего, включая командные модули и CDN для поиска зависимостей.

Чтобы демонстрация работала со страницами GitHub, я установил publicPath в конфигурации веб-пакета определенным образом Github.

Страницы индекса жестко закодированы со ссылками на определенный ресурс в CDN. Хотя они жестко закодированы для демонстрации, в нашей реальной системе мы добавили несколько конфигураций в конфигурацию веб-пакета, чтобы позаботиться об этом. Логика заключается в том, чтобы просмотреть зависимости package.json и автоматически вставить соответствующие элементы script или link на страницу индекса с указанной версией.

Исходный код доступен по адресу https://github.com/RohitRox/microfrontend-esnext-demo

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

О чем не сказано в этом посте

  • Таблицы стилей — мы экспортируем базовые стили как общие и используем их через CDN. Чтобы предотвратить переопределение и конфликты, мы запутываем имена классов CSS.
  • Несколько версий React — это решение не подходит для этой цели. Все наши микрофронтенды используют совместимые версии React и ReactDOM, поэтому мы используем общую версию. Мы не разрабатывали поверх устаревшего приложения и начинали с нуля, поэтому не сталкивались с этой проблемой.
  • SPA-маршрутизация. Маршрутизация React не подробно описана ни в этом посте, ни в демонстрации. Страница контейнера контролируется маршрутизатором, и если микроинтерфейсам необходимо контролировать пути к страницам, они делают это, взаимодействуя с контейнером через реквизиты, обратные вызовы или систему событий.

Ресурсы и дальнейшие исследования:

Есть комментарии, вопросы или отзывы, давайте свяжемся

Первоначально опубликовано на http://rohitrox.github.io 5 января 2020 г.