Микрофронтенд что это
Перейти к содержимому

Микрофронтенд что это

  • автор:

Подробное руководство по микрофронтенд архитектуре

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

Микрофронтенд — это архитектура, которая позволяет масштабироваться, делать команды независимыми и больше ориентироваться на бизнес потребности. Мы начинаем большую и подробную серию видео о микрофронтенд архитектуре на Boosty с ранним доступом. Некоторые темы будут эксклюзивно доступны только на Boosty по подписке. Мы будем читать и обсуждать книгу “Building Micro-Frontends. Scaling Teams and Projects, Empowering Developers”. Книга не переведена на русский язык. В этих видео мы будем обсуждать самую суть книги, без воды. Также я буду давать свои комментарии, основываясь на своем опыте внедрения микрофронтендов в большом проекте.

  1. Как распилить монолит на микрофронтенды
  2. Архитектуры фронтенд приложений — SPA, Изоморфные, Статичные, JAMstack
  3. Что такое микрофронтенд и каковы его принципы
  4. Что учитывать при переходе на микрофронтенд
  5. Краткий обзор видов разделения на микрофронтенды
  6. Вертикальное разделение на микрофронтенды
  7. Горизонтальное разделение на микрофронтенды
  8. Микрофронтенд на основе Module Federation
  9. Микрофронтенд на основе iframes
  10. Микрофронтенд на основе веб-компонентов
  11. Server Side микрофронтенды
  12. Edge Side микрофронтенды
  13. Проект с Webpack Module Federation
  14. Эволюция проекта с Webpack Module Federation
  15. Как деплоить микрофронтенды
  16. Как версионировать микрофронтенды
  17. CI/CD микрофронтендов
  18. Стратегии деплоя микрофронтендов
  19. Пример автоматизации пайплайна для микрофронтенда
  20. Общение микрофронтендов с бекендом
  21. Пример распиливания монолита на микрофронтенды. О приложении
  22. Пример распиливания монолита на микрофронтенды. Детали реализации
  23. Как презентовать микрофронтенд архитектуру команде

Микрофронтенд и Module Federation

7 месяцев назад · 6 мин. на чтение

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

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

Низкоуровневые концепции

  1. загрузка модуля (асинхронная)
  2. выполнение модуля (синхронная).

Высокоуровневые концепции

Каждая сборка действует как контейнер, а также потребляет другие сборки в качестве контейнеров. Таким образом, каждая сборка может получить доступ к любому другому предоставленному модулю, загрузив его из своего контейнера. Общие модули — это модули, которые являются переопределяемыми и предоставляются в качестве переопределений для вложенных контейнеров. Они обычно указывают на один и тот же модуль в каждой сборке, например, на одну и ту же библиотеку. Параметр packageName позволяет задать имя пакета для поиска requiredVersion . Он автоматически выводится для запросов модуля по умолчанию. Установите requiredVersion в false , когда автоматический вывод должен быть отключен.

Основные части

ContainerPlugin (низкий уровень)

Этот плагин создает дополнительную запись контейнера с указанными открытыми модулями.

ContainerReferencePlugin (низкий уровень)

Этот плагин добавляет конкретные ссылки на контейнеры как внешние и позволяет импортировать удаленные модули из этих контейнеров. Он также вызывает API override этих контейнеров для предоставления им переопределений. Локальные переопределения (через __webpack_override__ или override API когда сборка является контейнером) и указанные переопределения предоставляются всем контейнерам, на которые имеются ссылки.

ModuleFederationPlugin (высокий уровень)

ModuleFederationPlugin объединяет ContainerPlugin и ContainerReferencePlugin .

Какие цели преследует Module Federation

  • Должна быть возможность предоставлять и использовать любой тип модуля, поддерживаемый webpack.
  • При загрузке чанков должно загружаться все необходимое параллельно (за один запрос к серверу).
  • Управление от потребителя к контейнеру
    • Переопределение модулей представляет собой однонаправленную операцию.
    • Родственные контейнеры не могут переопределять модули друг друга.
    • Можно использовать в web, Node.js и т. д.
    • Всегда будет предоставлен, даже если не используется.
    • Будет разрешаться относительно config.context .
    • Не использует requiredVersion по умолчанию.
    • Предоставляются только тогда, когда они используются.
    • Будет соответствовать всем используемым равным запросам модулей в вашей сборке.
    • Предоставит все соответствующие модули.
    • Будет извлекать requiredVersion из package.json в этой позиции в графе.
    • Может предоставлять и использовать несколько различных версий при наличии вложенных node_modules .

    Примеры использования

    Отдельные сборки для каждой страницы

    Каждая страница одностраничного приложения предоставляется из контейнерной сборки в отдельной сборке. Оболочка приложения (application shell) также представляет собой отдельную сборку, ссылающуюся на все страницы как на удаленные модули. Таким образом, каждая страница может быть развернута отдельно. Оболочка приложения заново развертывается при обновлении маршрутов или добавлении новых маршрутов. Оболочка приложения определяет часто используемые библиотеки как разделяемые модули (shared), чтобы избежать их дублирования в сборках страниц.

    Библиотека компонентов в качестве контейнера

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

    Динамические удаленные контейнеры

    Интерфейс контейнера поддерживает методы get и init . init — это async метод, который вызывается с одним аргументом: объектом общей области (shared scope). Этот объект используется в качестве общей области в удаленном контейнере и заполняется предоставленными модулями от хоста. Его можно использовать для динамического подключения удаленных контейнеров к контейнеру хоста во время выполнения.

    // init.js (async () => < // Инициализирует общую область. Заполняет его предоставленными модулями // из текущего билда и из удаленных билдов await __webpack_init_sharing__('default'); const container = window.someContainer; // или получить контейнер откуда-либо еще // Проинициализируйте контейнер, он может предоставлять общие модули await container.init(__webpack_share_scopes__.default); const module = await container.get('./module'); >)();

    Контейнер пытается предоставить общие модули, но если общий модуль уже использовался, предупреждение и предоставленный общий модуль будут проигнорированы. Контейнер может по-прежнему использовать его в качестве запасного варианта. Таким образом, вы можете динамически загружать A/B-тест, который предоставляет другую версию общего модуля. Убедитесь, что контейнер загружен, прежде чем пытаться динамически подключить удаленный контейнер. Пример:

    // init.js function loadComponent(scope, module) < return async () =>< // Инициализирует общую область. Заполняет его предоставленными модулями // из текущего билда и из удаленных билдов await __webpack_init_sharing__('default'); const container = window[scope]; // или получить контейнер откуда-либо еще // Проинициализируйте контейнер, он может предоставлять общие модули await container.init(__webpack_share_scopes__.default); const factory = await window[scope].get(module); const Module = factory(); return Module; >; > loadComponent('abtests', 'test123');

    Динамические удаленные модули на основе промисов

    Как правило, удаленные модули настраиваются с использованием URL-адресов, как в этом примере:

    module.exports = < plugins: [ new ModuleFederationPlugin(< name: 'host', remotes: < app1: 'app1@http://localhost:3001/remoteEntry.js', >, >), ], >;

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

    module.exports = < plugins: [ new ModuleFederationPlugin(< name: 'host', remotes: < app1: `promise new Promise(resolve => < const urlParams = new URLSearchParams(window.location.search) const version = urlParams.get('app1VersionParam') // Эта часть зависит от того как вы планируете хостить // и версионировать ваши federated модули const remoteUrlWithVersion = 'http://localhost:3001/' + version + '/remoteEntry.js' const script = document.createElement('script') script.src = remoteUrlWithVersion script.onload = () => < // внедренный скрипт загружен и доступен через объект window // теперь можно зарезолвить Promise const proxy = < get: (request) =>window.app1.get(request), init: (arg) => < try < return window.app1.init(arg) >catch(e) < console.log('remote container already initialized') >> > resolve(proxy) > // внедрим этот скрипт с src с версионированным remoteEntry.js document.head.appendChild(script); >) `, >, // . >), ], >;

    Обратите внимание, что при использовании этого API необходимо зарезолвить объект, содержащий API get / init .

    Динамический publicPath

    Установка publicPath

    Можно разрешить хосту задавать publicPath удаленного модуля во время выполнения, предоставляя метод из этого удаленного модуля. Этот подход особенно полезен при подключении независимо развернутых дочерних приложений по подпути домена узла. Сценарий: У вас есть хост приложение, размещенное на https://my-host.com/app/* , и дочернее приложение, размещенное на https://foo-app.com . Дочернее приложение также монтируется на хост-домене, следовательно, ожидается, https://foo-app.com будет доступно через https://my-host.com/app/foo-app , а запросы https://my-host.com/app/foo-app/* перенаправляются https://foo-app.com/* через прокси-сервер. Пример:

    // webpack.config.js (удаленный) module.exports = < entry: < remote: './public-path', >, plugins: [ new ModuleFederationPlugin(< name: 'remote', // это имя должно совпадать с именем точки входа exposes: ['./public-path'], // . >), ], >;
    public-path.js (remote) export function set(value)
    // src/index.js (host) const publicPath = await import('remote/public-path'); publicPath.set('/your-public-path'); //bootstrap app e.g. import('./bootstrap.js')

    Вывод publicPath из скрипта

    Можно вывести publicPath из тега script из document.currentScript.src и задать его с переменной __webpack_public_path__ во время выполнения. Пример:

    // webpack.config.js (удаленный) module.exports = < entry: < remote: './setup-public-path', >, plugins: [ new ModuleFederationPlugin(< name: 'remote', // this name needs to match with the entry name // . >), ], >;
    setup-public-path.js (удаленный) // вычислите publicPath и установите его в __webpack_public_path__ __webpack_public_path__ = document.currentScript.src + '/../';

    Существует также значение 'auto' , доступное для output.publicPath , которое автоматически определяет publicPath для вас.

    Микросервисный подход в веб-разработке: micro frontends

    До недавнего времени JavaScript использовался для таких примитивных задач, как изменения цвета текста на странице. Веб начал стремительно развиваться, и, как следствие, сложность веб-приложений увеличилась. За последние 10 лет в веб перекочевало большинство программ, которые мы используем каждый день. Сейчас уже трудно представить свою жизнь без Google Drive, Google Docs, YouTube и т. д.

    В этой статье поговорим о микросервисном подходе в веб-разработке пользовательских интерфейсов.

    Типичное веб-приложение состоит из HTML-верстки, CSS-стилей и JavaScript-кода, который позволяет достичь максимального уровня интерактивности и отзывчивости. Чем выше сложность приложения, тем сложнее пользовательский интерфейс, а вследствие этого — и инструменты, которые нужны для его разработки. Именно поэтому фронтенд-разработка превратилась из простого набора дополнений для пользовательского интерфейса в сложную экосистему с большим количеством инструментов и высоким порогом входа.

    Проблема и решение

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

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

    • время разработки в связи с высоким уровнем сложности кода;
    • время тестирования;
    • временной интервал между релизами.

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

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

    Разработка новой функциональности в таком приложении, где большой объем устаревшего кода, с каждым годом становится все дороже для бизнеса. Со схожей проблемой уже сталкивались бэкенд-разработчики. Одно из решений большинства проблем монолитной архитектуры получило название «микросервисы» (Microservices).

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

    Помимо этого, можно выделить и другие достоинства микросервисной архитектуры в сравнении с монолитной:

    • модульность;
    • уменьшение времени на тестирование;
    • сокращение времени на деплой и возможность делать это параллельно;
    • возможность горизонтального масштабирования команды.

    А можно ли использовать микросервисный подход в веб-разработке пользовательских интерфейсов? Ответ: да! Можно и нужно! Именно такой подход и называют микрофронтенд (micro frontends).

    Микрофронтенд (Micro frontends)

    Микрофронтенд (micro frontend) — архитектурный подход, в котором независимые приложения собраны в одно большое приложение. Он дает возможность объединить в одном приложении разные виджеты или страницы, написанные разными командами с использованием разных фреймворков (см. рис. ниже).

    Источник

    Главные преимущества микрофронтенд-подхода — в разработке больших энтерпрайз-приложений:

    • модульная архитектура. Отдельные виджеты или страницы — это полностью независимые приложения;
    • скорость тестирования. Изменения в одном виджете или странице можно протестировать изолированно и только в этом приложении, не тратя времени на тестирование всего остального функционала;
    • параллельные деплойменты. Отдельные виджеты или страницы могут и должны деплоиться независимо.

    Помимо очевидных достоинств такого подхода, у него есть и существенные недостатки:

    • увеличение общей сложности приложения;
    • дублирование кода. Каждое приложение разрабатывается отдельной командой, которая принимает свои технические решения. Это ведет к повторной загрузке одинаковых фреймворков, библиотек и общему дублированию кода, который мог быть использованным повторно;
    • JS-бандл монолитного приложения всегда будет меньше, чем совокупность бандлов в микрофронтенд-архитектуре;
    • возможные проблемы с кешированием и версионностью приложений;
    • глобальные переменные или CSS-стили — это вещи, о которых стоит забыть в микрофронтенд-архитектуре, если приложения полностью не изолированы.

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

    К сожалению, пока не существует конкретной спецификации для построения микрофронтенд-архитектуры. Вот, пожалуй, самые доступные и простые способы и техники для построения микрофронтенд-приложений:

    • IFrames;
    • библиотека Tailor.js;
    • фреймворк single-spa.

    IFrames

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

    • производительность;
    • сложность поддержки.

    Библиотека Tailor.js

    Здесь вы можете прочитать больше о самой библиотеке. Компания Zalando создала целую экосистему для построения микрофронтенд-архитектуры, и Tailor.js — это часть экосистемы. Особенность Tailor.js — то, что это пакет для Node.js, и ориентирован он на построение микрофронтенд-архитектуры с серверным рендерингом.

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

    Single-spa

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

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

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

    • SystemJS — загрузчик модулей, который нужен для асинхронной загрузки отдельных приложений;
    • врапперы — single-spa предоставляет отдельные врапперы под каждый фреймворк, который создает обертку над приложением, нужную для интеграции и подключения отдельного приложения в общее single-spa;
    • API — single-spa предоставляет набор инструментов, которые нужны для коммуникации между отдельными приложениями, подписку на события и т. д.

    Типичное приложение с использованием single-spa выглядит так:

    А вот так выглядит коммуникация между отдельными элементами микрофронтенд-архитектуры, построенной с использованием single-spa:

    Источник

    Root Application — это корень приложения. Именно здесь происходит подключение sigle-spa как основного фреймворка, а также конфигурация SystemJS для корректной загрузки внешних приложений.

    Каждое дочернее приложение для корректной интеграции должно предоставлять публичные методы bootstrap, mount, unmount, которые используются фреймворком single-spa для мануального бутстрэппинга приложения. Почти под каждый современный фреймворк существует готовый враппер, который упрощает эту задачу и автоматизирует некую часть процесса. На сайте single-spa можно найти список всех фреймворков, под которые существуют готовые врапперы.

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

    Конфигурация билда для React.js под single-spa представлена здесь.

    import React from 'react' import ReactDOM from 'react-dom' import singleSpaReact from 'single-spa-react' import < property >from 'lodash' import setPublicPath from './set-public-path.js' const reactLifecycles = singleSpaReact( < React, ReactDOM, loadRootComponent: () =>import(/* webpackChunkName: "react-app" */'./App.js').then(property('default')), domElementGetter, >) export const bootstrap = [ () => < return setPublicPath() >, reactLifecycles.bootstrap, ] export const mount = [ reactLifecycles.mount, ] export const unmount = [ reactLifecycles.unmount, ] export const unload = [ reactLifecycles.unload, ] function domElementGetter() < let el = document.getElementById("react-app"); if (!el) < el = document.createElement('div'); el.id = 'react-app'; document.body.appendChild(el); >return el; >

    Используя существующий враппер single-spa для React.js, мы создаем интерфейс с методами bootstrap, mount, unmount, где соответственно описываем, как должно бутстрэппиться наше приложение. Враппер помогает инкапсулировать внутреннюю имплементацию и создать API для правильного подключения в single-spa фреймворка.

    Похожим образом это выглядит и для Angular 8.

    import < platformBrowserDynamic >from '@angular/platform-browser-dynamic'; import < Router >from '@angular/router'; import < AppModule >from './app/app.module'; import < environment >from './environments/environment'; import singleSpaAngular from 'single-spa-angular'; import < singleSpaPropsSubject >from './single-spa/single-spa-props'; if (environment.production) < enableProdMode(); >const lifecycles = singleSpaAngular( < bootstrapFunction: singleSpaProps =>< singleSpaPropsSubject.next(singleSpaProps); return platformBrowserDynamic().bootstrapModule(AppModule); >, template: '', Router, NgZone: NgZone, >); export const bootstrap = lifecycles.bootstrap; export const mount = lifecycles.mount; export const unmount = lifecycles.unmount;

    Так же, как и в случае с React.js, мы предоставляем интерфейс для ручного бутстрэппинга приложения на Angular 8.

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

       Root application    

    Две главные части, на которые стоит обратить внимание:

    • script-тег, в котором нужно описать маппинг названия приложения, на адрес, с которого single-spa будет подгружать amd-модуль для этого приложения;
    • script-тег, где нужно непосредственно зарегистрировать приложение с помощью метода registerApplication. Здесь нужно указать адрес, при переходе на который system.js будет загружать соответствующий модуль.

    Как можно увидеть, Root Application — простой HTML-файл с основными конфигурациями для загрузки других приложений. В одном микрофронтенд-приложении можно зарегистрировать множество микроприложений. Если при регистрации приложения в параметре метода registerApplication указать просто /, такое приложение будет загружаться для каждого доступного адреса. Именно такой подход желательно использовать для создания навигационной панели или частей приложения, которые являются общими и не должны загружаться повторно при переходе между приложениями.

    Полностью рабочий пример того, как это работает, можно найти в моем GitHub-репозитории.

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

    Нам, разработчикам, далеко не всегда приходится создавать приложения с нуля. Single-spa дает возможность полностью использовать существующие приложения как элементы микрофронтенд-архитектуры, будь то Root Application или асинхронно загружаемые микроприложения.

    Если из существующего приложения нужно создать микроприложение, совместимое с single-spa и имеющее возможность загружаться асинхронно, в первую очередь нужно искать соответствующий враппер. Для большинства современных фреймворков и библиотек single-spa предоставляет врапперы, готовые к загрузке через npm, а также документацию, описывающую, как их правильно настроить. Если же для используемого фреймворка не существует готового враппера, то всегда можно написать его самостоятельно. Настроив враппер и собрав amd-модуль, вы получите готовое к подключению микроприложение; все, что останется, это добавить соответствующую конфигурацию в Root Application. С собственного опыта скажу, что для современных фреймворков и библиотек, таких как Angular 2+, React, Vue, которые собираются с помощью Webpack, конвертация в микроприложение проходит быстро и без дополнительных «танцев с бубнами».

    Если из существующего приложения нужно создать Root Application, тогда в первую очередь нужно в index.html подключить библиотеки для single-spa и добавить все необходимые для загрузки других микроприложений конфигурации. После того как ваш index.html стал Root Application в single-spa, можно приступить к настройке остальной части приложения для корректной работы в single-spa-архитектуре так, как это описано в предыдущем абзаце.

    Проблемы и недостатки

    Большая проблема для обеих задач — это старые (legacy) приложения, написанные на старых фреймворках и собираемые с использованием старых инструментов. Например, приложение на AngularJS или Backbone, которое собирается с помощью gulp или grunt, может «сожрать» очень много вашего времени, прежде чем будет корректно сконфигурировано. С собственного опыта могу выделить следующие проблемные места:

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

    На этапе конфигурации проблемы, с которыми вы столкнетесь, будут самые разнообразные, поэтому запаситесь терпением 😉

    Кроме сложной конфигурации, выделим проблемы, которые могут возникнуть при построении микрофронтенд-архитектуры с использованием single-spa:

    • кеширование микроприложений. Без правильной стратегии по кешированию микроприложения, как и Root Application, будут кешироваться в браузере и игнорировать любые новые изменения, которые будут релизнуты;
    • дебаггинг. Если что-то не работает, дебаггинг без дополнительных конфигураций и надстроек может быть довольно тяжелым процессом, так как вам придется дебажить не приложения, а отдельные amd-модули без сорс мап;
    • общий размер приложения вместе со всеми асинхронными микроприложениями увеличится, в сравнении с монолитным подходом;
    • общая производительность микрофронтенд-приложения будет ниже, чем у монолита;
    • повторение кода. Повторная загрузка кода — как библиотек, так и целых фреймворков — ведет к ухудшению быстродействия всего приложения, а не только отдельной страницы. Single-spa дает возможность шарить зависимости между приложениями, но помните: чем больше у вас зависимостей, библиотек, компонент, которые шарятся между приложениями, тем больше ваша микрофронтенд-архитектура похожа на монолитную;
    • SEO-оптимизация. Загрузка отдельных приложений вместе с бутстрэппингом полностью проходит на клиенте, что значительно усложняет SEO-оптимизацию. Single-spa не поддерживает серверный рендеринг, для добавления поддержки можно использовать связку single-spa + Tailor.js.

    Выводы

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

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

    Все про українське ІТ в телеграмі — підписуйтеся на канал DOU

    Микрофронтенд что это

    Таким образом, подход МФ — это разделение монолитного фронта на отдельные кодовые базы, хранящиеся в отдельных репозиториях, к которым имеют доступ отдельные подкоманды. При этом у них могут/должны быть свои демонстрационные стенды, тесты и циклы выпуска. Соответственно, микрофронт — это съемная часть интерфейса. Разделять по страницам не обязательно, функционал может быть сквозным (например, корпоративный ui-kit).

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

    �� Микрофронтенд: что это такое и зачем он нужен?

    Микрофронтенды vs Ленивая загрузка

    И наоборот, стоит упомянуть ленивую загрузку по сравнению с МФ. Они решают разные задачи, но иногда люди думают, что все дело в одном, потому что в обоих случаях мы «расщепляем» приложение.

    Ленивая загрузка решает проблему производительности:

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

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

    Статья по теме

    Время сборки vs время выполнения

    Теперь поговорим о подходе объединения МФ в одно приложение. Что бы вы ни выбрали, для пользователя это должно выглядеть как единое приложение. Мерджить можно как на этапе сборки, так и динамически — во время выполнения кода на стороне пользователя.

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

    Время сборки Время выполнения
    Проверка типа + -
    Версии + не имеет смысла
    Независимое развертывание - +

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

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

    Управление версиями и независимое развертывание очень противоречивы:

    • Управление версиями означает, что вы можете взять любую версию МФ другой команды. Особенно это актуально, когда нужно провести дополнительную работу по обновлению зависимостей МФ от других. Каждая команда выбирает лучшее время для апгрейда.
    • Независимое развертывание дает больше автономии и независимости командам. Важно всегда использовать последние версии МФ. Это требует обратной совместимости.

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

    Далее мы увидим примеры конкретных реализаций каждого подхода к объединению МФ.

    Подходы к организации микрофронтендов

    iframe

    Самый старый способ организации МФ. iframe — это специальный тег для передачи адреса ресурса, который будет отображаться на основном сайте. В результате получается сайт на сайте.

    �� Микрофронтенд: что это такое и зачем он нужен?

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

    Эти преимущества достигаются за счет производительности, поскольку каждая вставка iframe приводит к нагрузке на ресурсы. Этого не избежать: попытки отладить и переподключить DOM-узел не сохранят ранее загруженные ресурсы, их придется скачивать заново. Вы можете свести к минимуму снижение производительности, настроив кэширование.

    Для этого вам необходимо настроить инвалидацию кеша на основе времени для неизменяемых ресурсов. К счастью, все современные cli из коробки к собранным файлам js и css прикрепляют к названию небольшой хэш. К недостаткам этого метода относится неспособность поисковых роботов отрисовывать iframe для последующего индексирования.

    Плюсы Минусы
    Простота реализации Производительность
    Логика и изоляция стилей SEO
    Независимое развертывание
    Фреймворк-агностик

    Статья по теме

    Веб-компоненты

    Фронтенд-сообщество давно ждало создания нативных компонентов, но в итоге они так и не обрели той массовой популярности, на которую многие рассчитывали. Три самых популярных фронтенд-фреймворка (React, Vue, Angular) по-прежнему создают компоненты по-своему.

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

    • Либо библиотеки Lit, либо Stencil недостаточно популярны и недостаточно распространены. Кроме того, на рынке не хватает специалистов, умеющих с ними работать или готовых учиться.
    • Экзотикой остаются угловые элементы или vue-custom-element. В нативной среде особого смысла их использовать нет. Если вы уже разбили приложение, то на обычные npm-пакеты, чтобы потом можно было подключать компоненты как угодно. Использование веб-компонентов с другими фреймворками неразумно, так как вместе с сгенерированными компонентами нужно подключить мини-версию фреймворка, на котором они были написаны.
    • Перенос сложных функциональных частей в веб-компоненты может быть дорогостоящим. Поскольку вам нужно будет настроить взаимодействие вашего компонента с остальной частью приложения, выделение целой страницы в отдельный пользовательский компонент может оказаться неоправданным.
    • Поисковые роботы не могут создать веб-компонент, и это повлияет на SEO-оптимизацию.
    Плюсы Минусы
    Подходит для сквозной функциональности Сложно реализовать
    Совместимость с любым фреймворком SEO
    Логика и изоляция стилей

    NPM

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

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

    Плюсы Минусы
    Производительность Не имеет независимого развертывания
    SEO Один стек
    Проверка типа
    Версии

    Подмодули git (или другой способ создания монорепозиториев, таких как Lerna)

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

    �� Микрофронтенд: что это такое и зачем он нужен?

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

    Давайте посмотрим на различия между двумя методами:

    • Пакеты NPM, по сути, являются конечным, умеренно изолированным микропродуктом со своими собственными выпусками и версиями. Все сосредоточено на создании повторно используемого функционала. Но приложение может быть сложным/запутанным и отторгающим, поэтому упаковка большого монолита может быть довольно дорогостоящей. Вот здесь было бы разумно рассмотреть сабмодули, потому что они позволяют очень грубо резать репозиторий, когда мы перемещаем папку в отдельный репозиторий без какой-либо дополнительной подготовки.
    • Пакеты NPM могут быть вложены рекурсивно. Подмодули тоже, но на уровне сборки могут начать дублировать функционал, если один из подмодулей включить несколько раз в разные папки как отдельный подмодуль. В этом случае стоит использовать более плоскую модульную структуру.
    • Если вам нужно быстро выкатить фичу сразу во все пакеты, кросс-пакетная разработка может оказаться крайне неудобной. Хотя в подмодулях все остается по-прежнему, вы можете вносить изменения, затрагивающие другие подмодули. В этом случае его легко отладить. Но в итоге сами изменения вы не сольете — на уровне мерж-реквеста сторонняя команда, чей модуль вы трогали, может потребовать от вас привести код в соответствие с их правилами.
    npm git подмодули
    Возможность повторного использования Черновая нарезка функционала
    Произвольно вложенные зависимости Плоская структура
    Кроссплатформенная разработка Разработка с любым количеством модулей

    single-spa

    single-spa — это, по сути, фреймворк, который объединяет другие фреймворки. Невероятно мощная технология, за которой скрывается огромное количество нюансов — тема для отдельной статьи.

    Схема аналогична iframe, но загрузка МФ теперь осуществляется через нативный импорт + importmap или через Systemjs, если нужны полифиллы.

    �� Микрофронтенд: что это такое и зачем он нужен?

    В отличие от всех методов организации МФ, этот очень заточен под объединение разных фреймворков под себя. Но стоит предостеречь от использования технологий ради самих технологий. Если есть возможность обойтись одним стеком, нужно его использовать. Разработка может быть навсегда обременена поддержанием технически сложного проекта и исправлением любых ошибок из-за побочных эффектов различных приложений. Пользователь может испытывать дискомфорт, т. к. количество кода для загрузки в клиент будет увеличено (ядра разных фреймворков под разные куски функционала + ядро ​​самого синглспа и его плагинов).

    Плюсы Минусы
    Независимое развертывание Большая документация, которая все же не охватывает все случаи
    Фреймворк-агностик Трудности с SEO
    Мощный интерфейс командной строки

    Webpack 5 Module Federation

    Плагин webpack 5, разработанный специально для создания МФ. Перспективная технология: небольшой плагин сборки для более корректной сборки и динамического импорта во время выполнения.

    Схема почти один в один повторяет singlespa, но теперь для загрузки МФ используется динамический импорт

    �� Микрофронтенд: что это такое и зачем он нужен?

    Плюсы Минусы
    Независимое развертывание Низкий уровень
    Легкая реализация
    Совместимость с SSR

    Как выбрать, что использовать в вашем случае?

    Давайте посмотрим, что можно применять и для чего:

    • iframe - единая вставка для комбинации несочетаемого;
    • веб-компоненты — когда нужен небольшой сквозной функционал без привязки к фреймворку, как корпоративный ui-kit;
    • пакеты npm — если есть возможность повторного использования между проектами и/или вам нужна проверка типов во время сборки;
    • git submodules — когда нужно грубо порубить проект и распределить зоны ответственности;
    • single-spa — когда есть острая необходимость комбинировать несколько фреймворков до бесконечности, желательно без SSR;
    • модуль-федерация — все остальные сценарии использования МФ при условии единства стека.

    Каждый подход хорош по-своему и всему должно быть свое место. Прежде чем переходить на МФ, советуем подумать, а действительно ли это вам нужно. Какой бы подход ни был выбран, он неизбежно что-то усложнит на уровне разработки, CI/CD или производительности. Если есть возможности остаться на едином стеке и монолитном приложении, с удовольствием этим воспользуюсь.

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

    Источники

    Состояние микрофронтендов

    Одна из наиболее противоречивых тем во фронтенд-разработке — это микрофронтенды. Заслуживают ли они внимания? Стоит ли на самом деле разделять приложение? Нужны ли они вам уже сегодня? А может это просто ещё один повод для консультантов заработать денег?

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

    Что такое микрофронтенды

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

    Главная проблема здесь в том, что эти части всегда потребляются или воспринимаются как одно целое.

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

    Есть несколько способов решить эту проблему. Наиболее простой из них заключается в замене модели передачи данных существующих API на HTML-вывод. Перемещение от одного сервиса (представления) к другому было бы просто гиперссылкой. Недостаток этого подхода в том, что, несмотря на работоспособность, в большинстве случаев он определённо не обеспечит желаемого пользовательского опыта.

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

    Хорошим вопросом здесь является взаимосвязь микрофронтендов с компонентами и модулями. Получается, что все эти принципы стремятся привнести некую переиспользуемость и ответственность в виде паттерна единицы работы (UoW). Единственное отличие в том, к какому уровню происходит обращение.

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

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

    Почему используют микрофронтенды

    Есть множество причин для их использования. Довольно часто главная причина носит технический характер, хотя в идеале за использованием микрофронтендов стоят реальные бизнес-кейсы (или кейсы для расширенного пользовательского опыта).

    Микрофронтенды применяются для того, чтобы:

    • отдельные части фронтенда могли разрабатываться, тестироваться и развёртываться независимо;
    • отдельные части фронтенда могли быть добавлены, удалены или заменены без повторной сборки;
    • разные части фронтенда могли быть созданы с помощью разных технологий.

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

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

    • В разработке фронтенда задействовано много команд.
    • Отдельные части должны активироваться, деактивироваться или развёртываться для конкретных пользователей или групп.
    • Внешние разработчики должны иметь возможность расширять UI.
    • Набор возможностей UI растёт ежедневно или еженедельно, не оказывая влияния на остальную часть системы.
    • Скорость разработки должна быть постоянной, несмотря на рост приложения.
    • Разные команды должны иметь возможность использовать собственные инструменты.

    Кто использует микрофронтенды

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

    • DAZN
    • Elsevier
    • entando
    • Fiverr
    • Hello Fresh
    • IKEA
    • Bit.dev
    • Microsoft
    • Open Table
    • OpenMRS
    • Otto
    • SAP
    • Sixt
    • Skyscanner
    • smapiot
    • Spotify
    • Starbucks
    • Thalia
    • Zalando
    • ZEISS
    • … и многие другие!

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

    Список растёт с каждым днём: начиная с консалтинговых компаний, вроде ThoughtWorks или HLC, и заканчивая провайдерами облачных услуг (SaaS), вроде SalesPad или Apptio. Однако ставки на эту технологию также делают и более консервативные компании. В качестве примера можно привести обладателя звания “Hidden Champion 2015” (скрытый чемпион) немецкую компанию Hoffman Group.

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

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

    Платформа Bit.dev и её маркетинговый сайт построены с использованием компонентов React, которые управляются при помощи… Bit.

    Взгляните на эту страницу. Вы можете навести указатель на разные её компоненты и увидеть их “исходные коллекции”. Кликните по имени компонента (сверху), чтобы просмотреть его и даже установить в свой проект.

    Эта страница построена из компонентов, разработанных в двух разных базах кода с GitHub: “base-ui” (см. коллекцию на Bit) и “evangelist” (см. коллекцию на Bit).

    Коллекция base.ui служит в качестве системы проектирования (также опубликованной с помощью Bit). Компоненты в коллекции evangelist (используется для маркетинговых страниц) задействуют некоторые из компонентов, доступных в base-ui, чтобы поддерживать единый внешний вид UI между различными микрофронтендами.

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

    Как создавать микрофронтенды

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

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

    Клиентские фреймворки

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

    Такой (или аналогичные) шаблон реализуют следующие фреймворки:

    Серверные фреймворки

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

    Такой же или аналогичный шаблон реализуют следующие фреймворки:

    Вспомогательные библиотеки

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

    Один из примеров — это обработка совместно используемых зависимостей посредством таких механизмов, как карты импорта или блоки, относящиеся к упаковщику.

    Следующие библиотеки помогают понизить количество рутинного кода:

    Будущее микрофронтендов

    В то время как некоторые люди видят объединение вещей с помощью вспомогательных библиотек, подобно модульной федерации (module federation), большинство остается неизменным к своим подходам. Радует, что многие фреймворки позволяют легко писать код, который не приводит к серьёзной зависимости от поставщика. Тем не менее недостаёт общего стандарта, который упростил бы обмен решениями хотя бы в техническом плане.

    Ещё одна вещь, которой пока что недостаёт ,— это принятие и более широкое освоение сообществом.

    Несмотря на то, что микрофронтенды набирают популярность, большая часть сообщества до сих пор пребывает в сомнениях.

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

    Заключение

    Доступное количество существующих решений и их пользователей во многих проектах по всему миру посылает мощный сигнал: микрофронтенды готовы к использованию! Я же рекомендую перед началом крупного проекта сначала ознакомиться с различными паттернами и решениями.

    • Как работает новый await верхнего уровня в JavaScript
    • Чистый код JavaScript — Вертикальное форматирование
    • Что значит this в JavaSсript?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *