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

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

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


Так же, как вижу, в каждом из модулей могут использоваться разные версии npm-зависимостей, что приводит к рассинхрону и потенциальным багам, часть из которых описана в статье. Вскоре может понадобиться изменить конфиги вебпака для отдельного модуля — добавить другие лоадеры, плагины, сборку других фреймворков и т.п., но, как я понял, Module Federation опирается на единый конфиг. Как планируется разруливать этот кейс?


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


В монолите, к сожалению, тоже есть одна существенная проблема — так как собирается все и сразу, то время сборки значительно увеличивается (хотя есть несколько стратегий для динамического билдинга), при Module Federation, как понимаю, будут собираться только переданные через cli модули или тоже все?

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

Модули могут, нет, модули должны лежать в разных репозиториях! Соответственно для каждого из микрофронтендов может быть свой релизный цикл, свой CI/CD, свои стенды, своё тестирование и т. д. Самое главное — не нарушать контракт между микрофронтендами.
Так же, как вижу, в каждом из модулей могут использоваться разные версии npm-зависимостей, что приводит к рассинхрону и потенциальным багам, часть из которых описана в статье. Вскоре может понадобиться изменить конфиги вебпака для отдельного модуля — добавить другие лоадеры, плагины, сборку других фреймворков и т.п., но, как я понял, Module Federation опирается на единый конфиг. Как планируется разруливать этот кейс?

В Module Federation есть механизм, который резолвит версии пакетов опираясь на semver. Webpack-конфиги у разных микрофронтендов свои, так что можно использовать любые лоадеры и плагины и фреймворки, теоретически, можно подружить React, Vue и Angular, если немного полколдовать с вставкой микрофронтенда на страницу, я как раз собираюсь это попробовать.
И по поводу «разделения зоны ответственности» непонятно, чем данная схема лучше монолита — если код разбит на асинхронно загружаемые модули, то команды, их разрабатывающие, и так не будут пересекаться по коду. Проблема только в том, что используется один гит-репозиторий, но если команд не больше 4, разруливается менеджерингом лейблов и веток — в одном проекте так делали, пересечений фактически не было.

Да, мы тоже рассматривали такой вариант, но подход с Module Federation оказался более привлекательным с точки зрения независимого развертывания, ведь мы не завязаны на релизный цикл монолитного проекта. В перспективе, команд у нас будет больше 4, так что тут Module Federation нас выручит.
В монолите, к сожалению, тоже есть одна существенная проблема — так как собирается все и сразу, то время сборки значительно увеличивается (хотя есть несколько стратегий для динамического билдинга), при Module Federation, как понимаю, будут собираться только переданные через cli модули или тоже все?

При Module Federation мы можем параллельно запустить сборку нескольких микрофронтендов, и это будет быстрее, если бы мы собирали монолит.

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


Тем не менее, недостатки, присущие проектам, разложенным по разным репозиториям и имеющим общие части остаются, но для 4+ команд по-другому и не получится — толпиться всем в одном репозитории становится тесно даже при грамотном менеджеринге веток, так как из-за разницы в релизных циклах мердж реквесты начнут копиться и устаревать. Можно сделать еще удобные рецепты, чтобы собирались только рут + нужные модули, этим разрулится проблема с производительностью. SSR тоже вполне можно прикрутить, включив в useDynamicScript механизм require и кэш в global, хотя прикрутить ожидание асинхронных вызовов перед рендером будет непросто (но наверняка будет еще немало подводных камней).


В общем, Module Federation на первый взгляд — уже хоть что-то, похожее на удобство, по крайней мере для одностековых проектов.

Микросервисы, микрофронтенды, кубернейтс. Бедные девопсы

Сейчас есть проект на работе, где нужны реализовать микрофронты + хост. Есть CI/CD и все тому прочее, проект крупный. Но «женить» это все очень больно, особенно, когда оказалось, что нельзя бить на чанки js дочерние модули (это из особо критичный проблем).
Кое-как франкенштейн работает, но сердце щимит от того, что есть Module Federation, который по сути решает кучу проблем, но…

Пробовал по-разному, полный шаринг всех пакетов в хосте и микрофронтах по Advanced API из примеров в репозитории, но «не повезло, не фортануло» (с). Кое-как адаптировал текущие решения из Module Federation к своему проекту и работать даже начало стабильнее, монтирование/размонтирование, по крайней мере, работает как часы

Заинтересовал config в ваше примере, о нем нет никакой информации. Может именно там есть что-то, что поможет мне :) Да и было бы интересно посмотреть на вашу демку

За статью спасибо конечно, хотя у меня навернулись слезы, потому что я не смог в Module Federation :(
Заинтересовал config в ваше примере, о нем нет никакой информации. Может именно там есть что-то, что поможет мне :) Да и было бы интересно посмотреть на вашу демку

оба конфига лежат тут github.com/oceanEcho/examples/tree/master/module-federation

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

Собаку съел (да что уж там, целую стаю собак) на федерациях, спешу поделиться.


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


Но к недостаткам:


  1. Вообще основные недостатки связаны с необходимостью что-то пошарить между модулями. Но этот конкретно — внедрение данных (в первую очередь, авторизации, но у нас это еще тема, локаль, окружение и какие-то системные вещи). Если коротко — все способы обладают теми или иными недостатками и компромисы кусаются. Мы остановились на системе поверх контекстов реакта, разве что весь контекст передается автоматически внутри аналога LazyService из статьи, но каждая федерация обязана быть обернутой в специальный метод. Главный принципиальный недостаток (помимо того что мы передаем ссылку на контекст внутри этого же контекста, хех) — сложность реализации вне реакта. А еще всё должно быть помещено внутрь реакт компонента, покуда вне его к контексту очевидно нет доступа. Но это отдельная большая тема, больше чем можно вместить в комментарий.


  2. shared из вебпака работает далеко не так радужно как хотелось бы. На самом деле некоторые пакеты очень требовательны к версии (реакт и реакт дом), для других (антд) мы генерируем общий файл стилей в зависимости от темы только один раз, как следствие, все остальные федерации так же должны использовать конкретную версию. Если коротко — есть набор пакетов, версия которых должна быть жестко зафиксирована и использоваться одинаковой во всех федерациях. Не было бы проблем, если бы package.json можно было бы наследовать, но, к сожалению, миграция пакетов на более новую версию та еще эпопея. И да, решить можно просто перестав шарить пакеты между приложениями, но тогда теряется смысл с федераций. Да и вообще, иногда кажется что с system.js было бы проще. П.С. history для реакт роутера обязан быть одинаковым во всей системе, и генерирует отдельный слой сложности.


  3. Иногда в голову приходит идея "давайте переиспользуемые компоненты вынесем в некий общий пакет, который будет использоваться всеми". В общем, работает только при правильно настроенном деплое этого общего пакета и только если в нем чистые глупые компоненты / функции. Иначе очень быстро всплывают проблемы синхронизации этого пакета из п.2, только в квадрате.



Это из крупных проблем. (Ну и еще избавить от momentjs который по волшебной причине игнорирует то что он шаренный и грузится в полном объеме в каждом пакете та еще задача, но это решаемо). Мелких камушков очень много, но они уже не так портят жизнь. Например, чтобы удобно запускать всё это локально пришлось написать свой собственный мини-сервер, который определяет запущенно локально и что нет и проксирует на локальный вебпак или берет с тестового стенда. Впрочем, один день работы на этот прокси, зато результат просто поразительный.


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

Ну и заодно как мы сделали:


Есть пакет который называется namespace/core, он подключается как обычный модуль ко всем федерациям, у него внутри три основные функции: ProvideFeredationContext, useFederationContext och RemoteComponent. Expose еще.


Первые два — собственно внедрение зависимостей поверх реактовских контекстов (главное отличие — он "выживает" внутри удаленного компонента).


Третий — принимает как аргумент модуль, который мы хотим внедрить, загружает его, монтирует в внутренний дивчик (ReactDom.render, сделано чтобы гарантированно разорвать все контексты внутри и предотвратить двойной контекст редакса, да и вообще мало ли), ну и передает контекст. expose — обертка над… экспортируемым реакт компонентом, необходимо для работы контекста (а еще создает контексты темы, локали и history для реакт роутера).


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


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


И еще одна раздражающая вещь, которую кажется можно решить, но как-то вот не решается:


const Foo = () => {
   const a = useContext(A);
}

const Bar = () => {
  const b = useContext(A);
  return <RemoteComponent module="..."><Foo /></RemoteComponent>;
}

Из-за разрыва контекста в RemoteComponent, а внутри Foo будет undefined. (Фуу мы передаем как ребенка внутрь чужой федерации по тем или иным причинам).

Еще хотел добавить что в воздухе витает идея прикрутить ShadowDom, но я так и не смог заставить стили (сгенерированные вебпаком) монтироваться в нужное место, поэтому пока живем без него.

Пока что выглядит так, что переход на Webpack 5 Module Federation решает проблему, которая стояла перед нашим стримом, а именно — разделение зоны ответственности и распараллеливание разработки.

А административными способами разделить и распараллелить разработку не дешевле и не надёжнее ли для бизнеса?
Команда А разрабатывает компонент\страницу А. Команда Б разрабатывает компонент\страницу Б. Разве это не более стабильное и практичное решение… По сравнению с теми многочисленными подводным камнями которые описаны в статье и которые ещё могут всплыть. Если «хранители знаний» этого добра уволятся — как будет это поддерживаться следующими поколениям разработчиков.
Что мы получаем?

Проблемы


Вы неплохо описываете. Но травматичный опыт работы со всем этим добром победить мне будет сложно. Увы (
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории