Как стать автором
Обновить

Микрофронтенды: зачем дробить фронтенд и почему это может быть хорошо

Уровень сложностиСредний
Время на прочтение15 мин
Количество просмотров10K
Всего голосов 24: ↑22 и ↓2+23
Комментарии29

Комментарии 29

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

  • китовые компоненты на основе ant design

  • авторизация (страницы авторизации/регистрации, интерсепторы для приватных запросов, хуки для работы с данными юзера, роутер гарды и подобное). Зависит от кита

  • биллинг (страница оплаты, хуки для работы с балансом пользователя). Зависит от кита и авторизации

  • пермишны (HOC обертки над кнопками, роутер гарды, хуки проверки и обновления доступов). Зависит от авторизации и биллинга

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

Интеграция в buildtime. Стейт менеджер - реактовский контекст. Модули общаются между собой только через фронт (так сложилось исторически). Есть rxjs синглтоны с подпиской и емитом евентов. Каждый модуль подписывается на нужное событие и самостоятельно обновляет данные с бекенда


Вопрос 1: руководство очень хочет module federation. Насколько это реализуемо, если не менять архитектуру? Я пока не могу понять, будут ли работать евенты и хуки в федерации. И будет ли общий кит на все модули или каждый модуль будет ставить себе ant design и раздувать чанки

Вопрос 2: в моей схеме не решен вопрос независимой разработки, чтобы, например, у разработчика был доступ только к биллингу и он мог запустить дев сервер только с ним и вести разработку. Разработчику выданы все доступы, он просто корневое приложение запускает и ведет разработку только в своем модуле. Из вариантов, которые я придумал - это создавать мини-корневое приложение, в которое будет подключен кит+авторизация и биллинг, но это тоже не полная изоляция и неудобно. Может подскажите, какие есть еще варианты?

Привет!

1) А почему хочет именно модульную федерацию? Чем аргументирует? В теории это можно сделать через shared, но в этом случае «независимость» будет условная, сценарий выглядит как неоптимальный, но точнее можно сказать если уточнишь почему просят именно модуль федереацию.

2) Те два варианта, что ты назвал — нормально абсолютно, через bun link или npm link залинкованные пакеты, ты поднимаешь хост приложение, меняешь только сурсы микрофронта, но дев сервер у тебя реагирует быдто бы меняется хостовое (потому что меняется зависимость) и ведешь разработку. Так можно и сразу несколько микрофронтов разрабатывать, а потом просто пушить изменения в соответствующие репы.

Еще один вариант — режим «хоста» у любого микрофронта, то есть сборка и деплой на отдельный стенд в режиме standalone приложения, тоже рабочая схема, отдельные скрипты в package.json настраиваешь и вперед.

Спасибо за вопросы!

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

2) Про режим хоста у микрофронта я как-то не подумал (видимо плохо гуглил). Выглядит как то, что мне надо
Спасибо за ответы.

1) Ну значит это осознанно, все причины на самом деле имеют право на существование. Поэтому желаю удачи в интеграции!

2) Не уверен, что многое из этого в принципе легко гуглится, особенно на русском, так что всегда рад подсказать! Лично мы это сами изобрели просто, без гугления.

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

Привет! Поднимать у себя хостовое приложение на дев-сервере, подключать необходимые микрофронты через link, если это buildtime, собирать локальную модуль федерацию в случае если это runtime. Очевидно всегда есть нюансы, это в общем.

А как вариант с proxy в webpack конфигах прям на любой нужный стенк(контур).

У нас по умолчанию все сразу с стенда берется, локально только ядро системы со всем обвесом и его бэк, плюс что-то в контейнерах. И потом разработчик уже смотрим с каким МЫ и БФФ ему раьотать , разворачивает их локально и прописывает в конфиг. Понятное дело конфигов может быть много, несколько задачь в параллель, такое бывает к сожалению. Но посыл про webpack proxy вроде ок

Тоже классно, кстати, да.

Это называется портлеты, на бэке уже всё придумали сто лет назад.

Что-то на энтерпрайзном, негибком и без реактивных фреймворков. Нам, любителям смузи, не подойдет. =)

Кста в микрофронтах. Когда их уже больше 200, релиз менеджер должен быть ращарбом, как будто XD И вы делали какой-то wizard CLI для генерации МФ или БФФ, типа CRA у React?

Было дело, делали, но его тоже нужно поддерживать, поэтому здесь всегда есть вопрос рентабельности.

В своё время очень плотно работал с микрофронтендами. Самой мозгодробительной задачей было сделать человеческий раутинг, когда микрофронтенд мог динамически добавлять чанки для навигации. А потом ещё по url восстанавливать состояние. Условно была раут: /user/1 по этому рауту открывается страница с пользователем с id=1. На этой странице могут быть несколько других микрофронтов. Каждый из этих микрофронтов добавляет навигацию. Условно вытащили новый "виджет (читай микрофронтовое приложение)", в этом виджете содержится, ну например, список тасок, она должна открываться по урлу /user/1/tasks, вытащили детали, должна открываться по урлу /user/1/details и т.д. Всё это должно было работать в динамике, внедрений было сотни, писались кастомные виджеты командами внедрения. Необходима была возможность всё это конфигурировать на лету и работать в рантайме, никакого билд тайм решения не годилось. Вот эту тему практически все статьи про микрофронтенды мягко обходят стороной, хотя на мой взгляд это одна из фундаментальных задач. Отвратительно, когда невозможно нормально восстановить состояние приложения из урлы, практически все решения что я видел забивали на это и реализовывали только верхний уровень навигации.

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

У нас это эволюционно случилось. В какой-то момент просто невозможно было иметь сотню пайплайнов для различных комбинаций сборок. Пришлось писать собственную платформу для управления микрофронтендами, где всё можно было наконфигурировать на джейсонах. Раутинг, кстати, тоже был полностью конфигурабельным и провайдился уже в движок. Сама платформа была на ангуляре написана, системные вещи (стейт, ивентбас, пермишен менеджер и тд) на пьюр js. Встраивать можно было микрофронты написанные на чём угодно, из коробки была поддержка vue, react и ангуляр. Но было апи для возможности что угодно встроить, реализуй билдер и провайдер (буквально 30 строк кода) и встраивайся.

Первую реализацию микрофронтов писали ещё на systemjs, тогда ещё мод феда не было в зачатке)

Личное предпочтение - это ориентироваться на библиотеки. Каждую страницу из примеров можно формировать как библиотеку. Библиотеки упрощают поддержку и управление версиями, используемых сторонних библиотек и фреймворков. Пример: используются разные версии angular в разных конечных продуктах, приложениях. Без обсуждения почему). Сборка монолита из кусков позволяет проконтролировать ошибки взаимодействий, провести оптимизацию сборки и многое другое. Среда исполнения в браузере единое. Не стоит забывать об этом, когда делаются аналогии с микросервисами. Не знаю как сделано в сбербанке, не смотрел код, похоже применяется что-то схожее с микрофронтедом. Бесит, что стилистика и взаимодействие с ui отличается от места к месту. Хотя не скажу,что там что-то сложное

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

Ниже представлена схема этого гипотетического проекта: продакты выделены голубым цветом, менеджеры проектов — оранжевым, бэкендеры — розовым и фронтендеры — зелёным.

При таком раскладе, естественно, всё будет через одно место. Интересно, где был их техдир, по мере того как оно росло до такой степени (начиналось же всё хорошо, как обычно). Уволить за профнепригодность.

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

Будьте готовы: контроль версий, обновления и совместимость станут вашей головной болью.

Так, может, и не надо тогда позволять "использовать те зависимости, которые им удобны и необходимы" - и не будет боли?

  • Отсутствие необходимости в независимых релизах

А разве где-то она есть - реальная необходимость в независимых релизах? Да, с одной стороны, заказчики/пользователи могут требовать новый футер через неделю, а новую корзину в апреле, но с другой - их требования 100% не всегда/редко/никогда будут один-в-один биться с границами ваших микрофронтендов (они ведь даже не знают, где эти границы проходят).

Однако, важнее всего понимать не как мы интегрируем микрофронты, а как они будут между собой взаимодействовать.

Вот это - самый главный вопрос, а всё остальное второстепенно и просто. Взаимодействие друг с другом и переиспользование общего кода.

При таком раскладе, естественно, всё будет через одно место. Интересно, где был их техдир, по мере того как оно росло до такой степени (начиналось же всё хорошо, как обычно). Уволить за профнепригодность.

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

Так, может, и не надо тогда позволять "использовать те зависимости, которые им удобны и необходимы" - и не будет боли?

Ну микрофронты разные, где-то есть яндекс.карты, где-то их нет, где-то эти яндекс.карты версии 2, а где-то уже версии 3. Вариантов же миллиард, реальная жизнь немного сложнее чем книги от O'Reilly и их ванильные примеры.

А разве где-то она есть - реальная необходимость в независимых релизах? Да, с одной стороны, заказчики/пользователи могут требовать новый футер через неделю, а новую корзину в апреле, но с другой - их требования 100% не всегда/редко/никогда будут один-в-один биться с границами ваших микрофронтендов (они ведь даже не знают, где эти границы проходят).

Конечно есть, представь просто, что условные Госуслуги.Авто вообще ничего не знают про существование Госуслуги.Паспорта, например. При этом для пользователя это вообще одни Госуслуги.

Вот это - самый главный вопрос, а всё остальное второстепенно и просто. Взаимодействие друг с другом и переиспользование общего кода.

Тут согласились 🤝

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

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

Ну микрофронты разные, где-то есть яндекс.карты, где-то их нет, где-то эти яндекс.карты версии 2, а где-то уже версии 3. Вариантов же миллиард, реальная жизнь немного сложнее чем книги от O'Reilly и их ванильные примеры.

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

Конечно есть, представь просто, что условные Госуслуги.Авто вообще ничего не знают про существование Госуслуги.Паспорта, например. При этом для пользователя это вообще одни Госуслуги.

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

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

Иногда нет бюджета везде заменить, тем более, что там (особенно с учетом неочевидной кластеризации и не только) достаточно много делов на апдейт.

Именно так в реальной жизни (а не книгах и статьях) чаще бывает - нужен одновременный релиз кучи всего, а не как в синтетических примерах, где новая фича требует обновления только Госуслуги.Авто, а всё остальное работает как и прежде.

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

Хороший материал, спасибо Александр

Могут ли микрофронтенды стать панацеей для всех проблем с масштабированием фронтенда? Был ли у тебя опыт работы с разными фреймворками в рамках одного проекта?

Спасибо за отзыв! :3 Панацеей точно ничего не может быть, всегда бывают нюансы. По поводу разных фреймворков — я сбоку видел проект на SingleSPA, работало хорошо, но сам такое не проектировал.

70 разработчиков фронт-приложения? Вы серьезно? 70 человек в состоянии написать 5-10 приложений, а не одно...

А если серьезно, надо выделить библиотеки(1-2-3-4), в которые вынести нефункциональный код. И нанять туда 4-5 сеньоров, такой команды достаточно, чтобы написать любую необходимую библиотеку.

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

Ну а чтобы писать функционал на метаданных можно уже брать мидлов и даже джунов. На все про все хватит 10-20 человек.

Итого у вас команда в 20-30 человек вместо 70. Управлять ими гораздо проще, менеджеров надо меньше.

Каждому из core team платить конечно придется значительно больше, но в целом ФОТ получится уменьшить раза в полтора. И никакие микрофронты не нужны.

Вуаля!

Не благодарите.

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

Весь этот объем работ ничего не принесет бизнесу и за него особо никто не заплатит в моменте, это нужно делать постепенно. По поводу генерации из метеданных — для больших админок работает, а когда это витринный b2c проект с ssr, то замучаешься генерировать.

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

Если проект рос постепенно, то еще проще развивать framework. Начиная с пяти разработчиков уже точно надо делить на функциональную часть и инструментальную. Часто уже при меньшем количестве разработчиков.

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

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

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

Тут согласен на все 💯

Возможно нубский вопрос, но как происходит получение данных с сервера у микрофронтов? Допустим, у меня 20 микрофронтов и 3 из них нужно получить данные о пользователе. Мы с каждого микрофронта шлем по запросу, но тогда вместо 1 запроса (как это было бы в монолите), получаем 3. Или запрос шлет хост-аппа и через шину передает эти данные нужным микрофронтам? Но тогда теряется независимость в релизах, потому что если это какой-то новый эндпоинт, то нужно сначала обновить хост, только потом микрофронты. А если хосту нужно будет откатиться, а микрофронты уже раскатаны... Как-будто оба варианта такое себе...

Отличный вопрос, спасибо!

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

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий