Всем привет. Меня зовут Михаил, я - фронтенд-разработчик в Лиге Цифровой Экономики.

В последнее время я пробую себя в должности руководителя направления фронтенд-разработки, однако я хочу с вами поделиться опытом разработки приложения с применением Webpack Module Federation, о том, какие задачи приходилось решать и проблемы, которые возникли на этом пути. Не буду вдаваться в теорию о микрофронтах и module federation, об этом уже много написано и предполагается, что вы знакомы с базовой настройкой. Мы же поговорим о самом «вкусном», некоторые моменты будут опущены в целях сосредоточения на деталях.

Вместо предисловия

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

  • Граф топологии доменов и сайтов

  • Удаленный рабочий стол прямо в браузере (noVNC)

  • Установка ОС, ПО на машины пользователей по сети

  • Управление пользователями, принтерами и др.

  • Подсистема оповещений через WebSocket и многое другое.

Однако, необходимо вернуться примерно на год назад.

Как все начиналось

Был обычный рабочий день, я тогда был еще рядовым разработчиком и трудился над другим проектом, который был на Vue. Как говорится, ничего не предвещало беды. Ко мне подошел тимлид и сказал: «Заканчивай задачи и как будешь готов, мне надо будет с тобой поговорить. Меня обдало холодным потом, потому как я только переехал из другого города и вышел с удаленки. В действительности, все оказалось несколько проще:

Итак, Миш, у нас новый проект. На React. Я хочу перевести тебя туда.

Да без проблем, - обрадовался я. – А что за проект?

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

Когда услышал про микрофронтенды
Когда услышал про микрофронтенды

Тут меня холодным потом обдало во второй раз. Дело в том, что в свободное время я с друзьями пишу пет-проект, если вкратце, то игровой сервер для GTA V на движке, в котором крутится Chromium Embedded Framework, а фронты (мы свои писали на React) выводятся как куча iframe один над другим и иногда возникала проблема шаринга состояния. По сути, очень похоже на те же микрофронты. Вспомнив всю боль, с которой я столкнулся в пете, я немного приуныл и стал ждать деталей.

От лирики переходим к деталям. Какие вводные я получил:

  1. Я один фронтендер на проекте.

  2. У заказчика есть MVP, необходимо «просто его доработать» (с)

  3. Фронт разделяется на ядро и дочерние приложения. Заказчик хочет в любой момент добавлять/удалять приложения без больших работ по фронту.

  4. У каждого приложения есть манифест – некоторая метаинформация + навигация 2 уровня и ниже. Этот манифест ядро запрашивает у сервера и тем самым отображает доступные модули системы

  5. У заказчика есть UI-kit

Как вы понимаете, некоторые пункты с течением проекта сильно изменились. Так, например, постепенно команда фронта в пике достигала 5 человек, а от MVP не осталось почти и следа.

Когда я получил MVP на руки, я полез «под капот» где я обнаружил самописный механизм подключения микрофронтов, который достаточно сильно связан со структурой манифеста приложения, а так же Babel и Redux Toolkit. Остальное было не так интересно.

Схема страницы. Header и Sidebar находятся в Core, Microfrontend - зона для дочернего приложения
Схема страницы. Header и Sidebar находятся в Core, Microfrontend - зона для дочернего приложения

По структуре MVP был просто монолитом, где в папке pages лежали отдельно микрофронты и все это через хитрую таску поднималось на нескольких локальных серверах – сервер ядра, проксирующий и заодно еще сервер с микрофронтом (в dev и watch режимах). Ядро стучало в проксирующий сервер в режиме разработки, который ходил локально в папку с микрофронтом и отдавал его. Выглядело все довольно странно, учитывая предпочтения заказчика и очевидной задачей от тимлида стал распил этого добра на отдельные репозитории.

Окончив всю эту работу, начался цикл разработки, но ситуация выше меня коробила. Список проблем, которые возникли в самом начале:

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

  2. Приложение монтировалось, но оставляло за собой кучу мусора, к тому же еще и не всегда корректно размонтировалось. Особенно остро вопрос мусора стал тогда, когда я заметил, что стили UI kit подключается банально тегом <style> в шапку и никак не удаляется и такая ситуация постоянно повторяется для каждого микрофронта

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

Микроинфаркты от микрофронтов

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

Поиски по теме микрофронтов дали неоднозначные результаты. С одной стороны, была куча информации о теории. С другой - почти ничего о практике. Тогда я наивно полагал, что уже сформированы лучшие практики, но реальность оказалась плачевной. Естественно, тогда чуть ли не из каждого угла трубили о Module Federation, и я думал быстро запрыгнуть в паровоз хайпа и умчаться в светлое будущее, которое умные дяди и тети проложили до меня. Отдельно отмечу, что Single SPA тогда странным образом прошел мимо меня, но Module Federation сильно меня зацепил, т.к. в нем я увидел едва ли не решение всех своих проблем:

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

  • Можно избавиться от дополнительного локального сервера для разработки

  • В локальной разработке я сильно ближе становлюсь к реальным условиям работы

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

Естественно, сразу же перейти на Module Federation не получилось. Почти потеряв надежду, т.к. я потратил 3 недели (точнее выходных по субботам и воскресеньям) на адаптирование приложений и не получалось ничего. Работал и прототип тимлида на своем механизме и примеры с гитхаба Module Federation, но именно мой проект не работал. Я долго анализировал сначала код, потом конфиги вебпака и не найдя очевидных ответов я попросту решил с 0 переписать приложения. И… оно заработало!

Микроинфаркт №1. Настройка Webpack

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

const ModuleFederationPlugin = require('webpack').container.ModuleFederationPlugin;

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'app1',
    }),
  ],
};

И в дочернем приложении:

const ModuleFederationPlugin = require('webpack').container.ModuleFederationPlugin;
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'app2',
      filename: 'remoteEntry.js',
      exposes: {
        './Widget': './src/Widget',
      },
    }),
  ],
};

Казалось бы, что тут не так? Да все тут так, но проблема оказалась всего лишь в одной строке и не в этом месте:

PublicPath в output критичеcки важен!
PublicPath в output критичеcки важен!

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

Мои попытки разобраться с Module Federation
Мои попытки разобраться с Module Federation

Микроинфаркт №2. Загрузка дочерних приложений

Первая проблема решена – микрофронты заводятся, все хорошо. Кроме одного: необходимо вручную прописывать все приложения. По сути, в этом ничего плохого нет, но это никак не коррелирует с требованиями ТЗ, да и в последствии все дописывать руками тоже лень.

Вторая проблема заключалась в том, что все-таки надо делать загрузку динамически, учитывая манифест. Сам манифест выглядит следующим образом:

{
  "id": "someapp",
  "moduleName": "SomeApp",
  "entrypoint": "someapp.js",
  "menuItem": {
    "path": "/foo",
    "label": "Бла-бла",
    "description": "какое-то описание",
    "icon": "hi",
    "options": [
      {
        "label": "2 уровень навигации",
        "path": "/bar"
      }
    ]
  },
  "routerPath": "/app",
  "weight": 1
}

Это уже конечная вариация манифеста любого дочернего приложения и все-бы ничего, но в конце марта прошлого года не было никаких подсказок о том, как делать динамику. В разделе advanced api был пример, вокруг которого я начал придумывать свой велосипед, но вместо колес получались квадраты. И примерно в конце апреля, когда я уже во второй раз думал бросить все, я наткнулся на статью, из которой честно стырил позаимствовал и механизм динамической загрузки (части кода можно найти на гитхабе и документации webpack), и хук по загрузке скриптом, который полностью разрешил проблему «мусора» в <head>.

Микроинфаркт №3. Состояние

Redux. Как много было о нем написано и сказано, и, наверняка мне достанется в комментариях за слова ниже, но все-таки я осмелюсь. Очевидна идея объединения сторов приложений и недолго копая я наткнулся на Redux Reducer Injection Example. Вроде бы все классно, но тут возникли самые большие сложности с адаптацией.

Я в попытках объединить состояния приложений
Я в попытках объединить состояния приложений

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

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

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

В-четвертых, а почему бы просто не передавать стор сверху вниз, а не снизу вверх? А также вообще объединить их, одновременно оставив независимыми.

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

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

Микроинфаркт №4. Роутер, роутинг и history

На самом деле это не столько проблема Module Federation, сколько, наверняка, я ошибся в проектировании и пересборке приложения из MVP. Например, у меня напрочь отказался работать BrowserRouter при монтировании дочернего приложения, при этом HashRouter работает как надо. И из-за некоторых ошибок при построении роутов пришлось держать 2 разные версии history для хоста и дочернего приложения из-за проблем энкодирования кириллицы в URL и передачи некоторых параметров в Django. Если у кого есть мысли не этот счет, был бы рад услышать какой вы используете роутер.

Микроинфаркт №5. Шаринг модулей

Не думаю, что станет откровением тот факт, что шаринг модулей – это киллер-фича Module Federation. Давайте посмотрим на опции в конфиге:

  1. eager – говорит о том, что данный модуль необходимо «жадно» потреблять при старте приложения. Без него микрофронт отвалится.

  2. singleton – указывает, разрешено ли иметь более одного инстанса модуля в окне

  3. requiredVersion – сравнение версии инстанса модуля в окне. При одинаковых модулях, но разных версиях отдается предпочтение более свежему.    

В целом, мой конфиг для дочернего приложения выглядит так:

const { ModuleFederationPlugin } = require('webpack').container;
const deps = require('../package.json').dependencies;
const { moduleName, entrypoint } = require('../src/static/app-manifest.json');

module.exports = function (isProduction) {
  return {
    plugins: [
      new ModuleFederationPlugin({
        name: moduleName,
        filename: entrypoint,
        exposes: {
          [`./${moduleName}`]: `./src/${moduleName}`,
        },
        shared: {
          react: {
            requiredVersion: deps.react,
            eager: !isProduction,
            singleton: !isProduction
          },
          axios: {
            requiredVersion: deps.axios,
            eager: !isProduction,
            singleton: !isProduction
          },
          mobx: {
            requiredVersion: deps.mobx,
            eager: !isProduction,
            singleton: !isProduction
          },
        },
      }),
    ],
  };
};

От конфига хоста он отличается лишь наличием флага isProduction и в таком виде его легко тиражировать по другим приложениям.

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

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

Еще одна проблема – плохая подготовка библиотек. Не хочется говорить об этом открыто, но стоит отметить, что при неправильной организации библиотеки она может вывалиться в remoteEntry целиком и полностью вместо того, чтобы упасть в свой чанк. И тут вы можете потерять еще одно преимущество – вместо того чтобы тянуть по сети небольшой файл, вы тянете огромный чанк. Так, например, при переходе на Module Federation мною было замечена уменьшение траффика на дочернее приложение с 500 на 40кб в ранних версиях (к сожалению, скриншоты потерял, придется верить на слово и не только мне), но однажды ситуация изменилась в худшую сторону.

Микроинфаркт №5. Code splitting

И, наверное, последняя проблема, с которой я столкнулся – разбивка кода на чанки. Так, на очередном цикле работы, я решил заняться оптимизацией приложения и под нож у меня попал babel, т.к. не давал адекватно протестировать приложение в условиях плохого соединения. «Скачивание» 20мб девелопрских ассетов по 3g как раз хватит выпить пару кружек кофе и поэтому на его место пришел esbuild, который параллельно вытеснил собой и Terser. Но, прописав ручные чанки все дочерние приложения упали с ошибкой. Я грешил на esbuild, но оказалось, что Module Federation не дружит с такой оптимизацией, т.к. сплитит самостоятельно. Решилась ли эта проблема на сегодняшний день я не знаю.

Вместо выводов

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

Скорее, я дам самому себе несколько советов, если придется работать с Module Federation, и не только:

  1. Пересмотреть способ организации работы со стейтами. Сейчас у нас все очень похоже на dependency injection, но как-то криво, на мой взгляд. Если двигаться по этому пути, то опробовать, например, Inversify. Если посмотреть под другим углом, то попробовать событийно-ориентированный стейт-менеджер. При поиске я наткнулся на Storeon, выглядит интересно, но никаких демок я не делал. Или же вообще общение между микрофронтами вынести в worker, хотя на первый взгляд выглядит как оверхед, но в пет проекте есть нечто подобное.

  2. Подготовить shared-библиотеки. И не одну. И сразу. Дело в том, что, работая над микрофронтами, все-равно что-то может повторяться в дочерних приложениях и лучше сразу уносить это в одну точку, т.к. в начале проекта мы не задумывались ни о переиспользовании логики, ни о переиспользовании компонентов, не смотря на ui kit. И так же стоит учесть, что лучше отделить логику от ui, потому что можно столкнуться с неожиданным поведением, напимер, «отвалы» контекстов, на которые многие жалуются, но с таким я не сталкивался. И в целом, лично мне нравится подход dumb components, не раз себя оправдывал.

  3. Абстракции. Как только появилась мысль сделать абстракцию – надо её делать, а не откладывать на потом. Естественно, в пределах разумного. К сожалению, я сначала думал отделаться «малой» кровью, пришлось писать сразу 3 и быстро их интегрировать.

  4. Оптимизация приложения. Да, преждевременная оптимизация – плохо. Но тогда не будет сюрпризов, например, с чанками, которые постигли меня. Необходимо даже на промежуточных этапах гонять бенчмарки и по возможности оптимизировать то, что есть. Особенно Core Web Vitals, потому что проход напрямую в точку, где происходит монтирования микрофронта может стать очень долгой операцией, и, если вовремя не отследив просадку производительности, можно получить ситуацию необходимости очень трудоемкого рефактора. Сетевые метрики тоже еще никто не отменял.

  5. Делать приложения абсолютно независимыми. Module Federation прекрасно позволяет это сделать - разрабатывать и использовать приложения отдельно и независимо очень круто! Но тут вырастают накладные расходы на Developer Experience, т.к. у меня была ситуация с dead code в продакшн сборке, и, каюсь, не везде удалось его убрать в силу разных причин. Так же, могут вырасти расходы на CI/CD и инфрастуктуру, но мы обошлись простым деплоем каждого приложения отдельно через Jenkins.

  6. Тесты. Просто потому, что было прямое указание. Мы тесты не писали. Как оказалось в последствии, очень зря и я очень жалею, что и тут я думал, что «пронесет».

  7. Репозитории. Следить за 11 репозиториями фронта в какой-то момент становится очень сложно. Что с этим делать - пока не ясно, но взгляд устремляется в сторону монорепозитория.

На этом у меня все, всем спасибо за внимание и успехов!

Комментарии (21)


  1. marshinov
    08.02.2022 22:18
    +3

    А в итоге зачем на проекте требовались микрофронтенды?


    1. skeevy Автор
      08.02.2022 22:42
      +1

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

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

      Целевая аудитория - системные администраторы, и у них есть разные уровни доступа. По требованиям ТЗ предполагается, что могут быть как локальные админы (администраторы структурной единицы в предприятия), так и супер админы (админ всего предприятия/нескольких предприятий, хоть всей РФ). Одни должны настраивать пул доменов, NTP, DNS и т.д., другим же достаточно предоставить доступ к управлению машинами, пользователям, принтерам.
      При этом, объем системы большой и изменение в функционале точечно затрагивают модули, снижая время на CI/CD и вывод в релиз отдельных элементов системы или выноса функционала в отдельный домен.
      К сожалению, были моменты корректировки ТЗ и на одной из крупных подсистем было очень много стихийных изменений, и мы бы уперлись в конфликты в репозитории и ожидании развертывания без микрофронтов, dev-стенд вообще по несколько раз в час обновлялся.

      Так же, сильно ускорилась работа, были сформированы несколько команд/одиночных разработчиков, работающих абсолютно независимо друг от друга, без ожиданий очередей сборки с минимальными конфликтами в git

      Более конкретно рассказать не могу, чтобы не получить по голове за разглашение :)

      Надеюсь, ответил на Ваш вопрос, если нет, то уточните, где я свернул не туда


      1. marshinov
        08.02.2022 22:47
        +1

        Микрофроненды нашли хорошее применение в организации ролевого доступ к АРМ. Как я говорил в статье, у каждого приложения есть манифест и сервер о них знает. 

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

        Так же, сильно ускорилась работа, были сформированы несколько команд/одиночных разработчиков, работающих абсолютно независимо друг от друга, без ожиданий очередей сборки с минимальными конфликтами в git

        Вот тут сборка - да, а все остальное через feature modules можно решить.


        1. skeevy Автор
          08.02.2022 22:56

          Ну здесь можно и клеймами в JWT решить

          Вы совершенно правы, но, как говорится, кто платит - тот и музыку заказывает :)

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

           остальное через feature modules можно решить

          Если я не ошибаюсь, feature modules предполагает нахождение на одном сервере, а module federation позволяет тянуть части системы из любого места. Поправьте, если не прав.


  1. marshinov
    08.02.2022 23:04

    приложение на любом стеке и "вклинить" его в существующую систему

    Мухаха, оно конечно "вклинивается", но без single spa роуты делать больно:)

    Если я не ошибаюсь, feature modules предполагает нахождение на одном сервере, а module federation позволяет тянуть части системы из любого места

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


  1. movl
    09.02.2022 00:20

    Смотрели ли на NX, и если да, то почему выбрали webpack module federation?


    1. skeevy Автор
      09.02.2022 10:05

      начал смотреть на NX, но слишком поздно, под конец проекта. На другом проекте обкатывают коллеги лерну и она им больше не нравится, чем нравится. Думаю, NX будет следующим. Но это история не про module federation

      Сам module federation выбрал по нескольким причинам:
      1) Шаринг зависимостей. Не нужно писать костыли для определения инстансов бибилиотек.
      2) Подкупили утверждения автора технологии по поводу экономии сетевого трафика и это на самом деле оказалось правдой
      3) По сути, конфигурация простая, но выглядит заковыристо. Пару строк в конфиг вебпака, бутстрап для энтиропоинта - и микрофронтенды готовы к работе
      4) Я слишком буквально воспринял фразу "подключить любое приложение в любой момент". Никто другой не мог на тот момент предложить, что можно встроить без костылей и лишних библиотек/фреймоврков механизм работы с приложениями. Да, было что-то уже в вебпаке плагинчик (не помню как называется), который позволял делать схожее, но причина ниже. Я ориентировался на то, что завтра/полгода/год с бухты-барахты заказчик притащит команду ангулярщиков, а мы все пишем на реакте (реакт был в требованиях тз). И нам как-то придется всем месте жить, а бизнес слышит про микрофронты и думает, что все просто.
      5) У меня была абсолютная свобода действий. Я люблю работать с новыми библиотеками, и тут подвернулся такой шанс. Хотя, возможно, сейчас бы я не стал так рисковать как год назад. А тогда я увидел новую хайповую фичу и решил попробовать.

      Да и возможно выбор module federation был yolo-решением и, слава богу, оно сыграло и опрадалось. Но, опять же, впредь я вряд-ли рисковать буду таким образом


      1. movl
        09.02.2022 12:51
        +2

        Мы в итоге пришли к NX. Изначально на основном проекте была своя система сборки модулей, на основе вебпака. Потом сделали свои плагины на основе DllPlugin от вебпака, чтобы части приложения можно было подключать через манифесты, в то время module federation еще пока не было. Это позволило перейти в монорепозиторий на лерне, и в дальнейшем на сборку ангуляром с кастомными скриптами под вебпак. Сейчас собираемся перейти на NX, так как в других проектах он себя хорошо показывает. Я правда не знаю, на сколько хорошо NX интегрируется с проектами на реакте, но с ангуляром снимает очень много головной боли.

        Я ориентировался на то, что завтра/полгода/год с бухты-барахты заказчик притащит команду ангулярщиков, а мы все пишем на реакте

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

        В целом было достаточно интересно почитать про ваш опыт. Спасибо.


      1. Dartess
        09.02.2022 21:15

        Лерна вроде депрекейтед


        1. skeevy Автор
          09.02.2022 23:04

          Тут ничего сказать не могу, но по отзывам куча issue на гитхабе открытых, которые никак не решаются, так что я лично не хочу с лерной связываться


  1. skeevy Автор
    09.02.2022 13:06

    Сейчас собираемся перейти на NX, так как в других проектах он себя хорошо показывает

    Я видел, что NX не поддерживает отдельные релизы подсистем, это дейтсвительно так и насколько больнно делать свои workaround'ы для этого?
    У нас каждый фронт релизится отдельно, интересно попробовать спроецировать этот опыт на будущее и подготовиться :)

    я так понял вы и сами с этим частично столкнулись

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

    Спасибо за ваш отзыв!


    1. skeevy Автор
      09.02.2022 13:07

      @movlпромахнулся веткой, извините


  1. LFFATE
    09.02.2022 22:58
    +1

    Мне не понравилась федерализация. Топорно, сложно, тяжело типизировать. Если нет требования поддержки старых браузеров, проще построить расширения на базе обычных esm. Гибкости больше. И контроля.


    1. skeevy Автор
      09.02.2022 23:03

      А с чем конкретно возникла сложность в типизации? У нас были проблемы в типизации бутстрапа (устали костылить и влепили мужицкий ts-ignore) и точку входа в дочь, если меняется стор ядра (приходится генерировать .d.ts и перекладывать руками в common), а так в остальном проблем не было


      1. LFFATE
        11.02.2022 11:05

        дык, при потреблении федерализации откуда типы брать? насколько помню, официальный ответ на гитхабе был в духе "нет совместимости с тайпскриптом". Ну и нет совместимости у федерализации с остальными сборщиками. Что привязывает консьюмеров к вебпаку. Хотя нормального экспорта в esm у вебпака по-моему до сих пор нет. Активно тестят и пишут в соответствующий ишью на гх, слежу в полглаза, но кажется, всё ещё не для прода.

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

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

        Ну и возвращаясь к типам - чтобы консьюмить модули с типами, генерю для каждого модуля d.ts и кладу его в кастомную папку с типами, которая работает как node_modules, импортирую модули как обычные модули из node_modules, в мапингах зависимостей коллбек в духе "если модуль начинается с project-name-*, то рерайтим импорт "вот так". Где "вот так" - динамический импорт esm. Да, он возвращает промис, то top level await тоже уже давно не диковинка.


        1. skeevy Автор
          11.02.2022 11:32

          Ну и нет совместимости у федерализации с остальными сборщиками. Что привязывает консьюмеров к вебпаку.

          а должна быть? Сборщик запилил такую вещь и логично, что завязывает на себя, чтобы пополнить комьюнити. Почему это не делают другие - вопрос. Хотя, судя по настроениям - не вопрос, ведь большинству либо страшно браться, либо "фу-фу, нафиг надо" .
          Для сборки приложенек - вебпак, для сборки либ - роллап. Для меня ну вот вообще не проблема привязки к сборщику. Можно, конечно, приплести сюда snowpack, vite и все остальное, но для меня скорости стало достаточно, отказавшись от babel в пользу esbuild, а если надо будет собрать все лучшее - там где-то еще должен жить gulp, можно велосипед из сборщиков вокруг него построить, только зачем?

          дык, при потреблении федерализации откуда типы брать?

          я уже выше писал, что из коммон либы я в своем случае складывал. Неудобно, но не смертельно, либо подцепить кастомную types в tsconfig (что, видимо, вы и сделали).

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

          Лежат точно так же в объекте, но не глобальном, если не указывать scope default. Каждый микрофронт может искать в отдельном скопе себе зависимости и выбрасывать туда, если нет зависимостей


          У каждого выбора есть свои сильные и слабые стороны. В случае моем, все сильные стороны перекрыли слабые. И я в целом остался доволен, а предупредить про неприятные моменты - вот цель статьи, потому что нигде это не освещается практически


  1. uyrij
    09.02.2022 23:53

    В чем была проблема хешей для имён в JS/CSS ? Это webpack или любой сборщик автоматом же должны уметь в билде?


    1. skeevy Автор
      10.02.2022 00:06

      Нет, просто в хост приложении загружается uikit и шарится в микрофронт. Сответственно, инжектятся стили с хешами версии ядра.
      В микрофронте приложении uikit потребляется из хоста, но если версия будет, например, младше хоста и меняли, допустим, инпут или таблицу - стили отлетали, т.к. в дочернем приложении ожидаются другие хеши для css классов (использовались scss modules). Это как раз случай, когда, вероятно, использовать singleton для библиотеки не лучшее решение, но у нас uikit непонятным образом весит больше 2мб (точнее понятным - некоторую графику загнали в base64 в css и еще куча других проблем) и это мрак полный. Пришлось смириться и быть внимательным, чтобы обновлять единомоментно

      Проблема тут еще в том, что uikit нам поставляли со стороны и информациооная поддержка была не лучшего качества - очень долго выбивали ченджлоги, в итоге пришли к тому, переодически высалаются PDF (!!!!) с описанием изменений, про сторибук молчу, больше выглядел как лишняя примочка не понятно для кого


      1. uyrij
        10.02.2022 06:44

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

        У вас реальный проект. ????


  1. aderbin
    10.02.2022 15:23
    +1

    У заказчика есть MVP, необходимо «просто его доработать» (с)

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



    1. skeevy Автор
      10.02.2022 15:25

      К сожалению, такое случается :)

      Когда заказчик узнал, что от MVP ничего не осталось, его удивлению не было предела :)