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

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

В ДОМ.РФ мы создаем продукты для рынка недвижимости, в частности предназначенные для электронного взаимодействия между застройщиками, банками и государственными органами. Задачи и цели систем отличаются друг от друга, но их объединяет общий дизайн. Безусловно, создание библиотеки UI-компонентов с нуля в каждом новом сервисе является крайне сомнительной идеей по следующим причинам: 

  1. Стоимость разработки заметно увеличиваются; 

  2. Сроки разработки также увеличиваются; 

  3. Консистентность: возникает проблема поддержки UI в одном виде.  

Казалось бы, создание отдельной библиотеки компонентов с вынесением всех UI-элементов в нее с возможностью дальнейшего подключения на проектах решает вышеперечисленные проблемы. Но что делать, если необходимо поддерживать определенные элементы библиотеки в актуальном состоянии на всех проектах одновременно в real-time? 

Изображение 1. Виджет Topline 

Один из таких элементов в нашей библиотеке компонентов – виджет Topline

Если кратко, то он представляет собой совокупность некоторого количество компонентов, реализующих некую логику и подразумевающих использование на клиенте “из коробки”. 

Но почему бы не вынести виджет в NPM-пакет и подключать его, как остальные элементы из UI-kit? Проблема заключается в том, что, с одной стороны, данный элемент периодически обновляется - например, добавляется новый сервис в боковую панель, который нужно отобразить на всех остальных проектах, или добавляется новый функционал, а с другой стороны, Topline должен быть актуальным абсолютно на всех проектах.   

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

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

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

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

Как эта технология может решить проблему с нашим виджетом? Одно из основных достоинств данного инструмента – подключение элементов в runtime. Это означает, что мы можем настроить интеграцию виджета таким образом, что при использовании сервиса у нас всегда будет подгружаться актуальный бандл с виджетом Topline.  

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

Пример подключения  

Подключение в конфиге вебпака нужного модуля:  

plugins: [ 

  name: 'eisgs_topline',
  remotes: {
    eisgs_topline: `eisgs_topline@${process.env.TOPLINE_URL}`,
  },
  shared: {
  react: {  

    eager: true,  

    requiredVersion: packageJsonDependencies.react  

    },
  }, 

] 

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

Также можно указать набор зависимостей с помощью shared, которые будут переданы из клиента в виджет (аналог Peer Dependencies).  

На клиенте виджет подключается следующим образом:  

<Topline   
  navConfig={navConfig}   
  profileConfig={profileConfig} 
/>  

Подключаться модуль будет асинхронно, поэтому необходимо обернуть его в <Suspense>: 

const ToplineModule = lazy(async () => import('eisgs_topline/topline')); 

<Suspense fallback={<>Loading…</>}> 

  <ToplineModule
    navConfig={navConfig}
    profileConfig={profileConfig}   
  /> 
</Suspense>  

 Более подробную информацию о подключении можно найти в документации Webpack. 

Изображение 2. Виджет Topline в реальном проекте. По сравнению с изображением №1 был добавлен функционал сервиса уведомлений.  

Что делать, если возникли проблемы с подключением через федерации?  

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

Для этих целей мы также публикуем виджет Topline в NPM, который подключается, если возникли проблемы с Module Federation:  

const ToplineBoundary = () => (   
  <ToplineErrorBoundary fallback={<ToplineFallback />}>     
      <ToplineModule />   
  </ToplineErrorBoundary> 
);  

При возникновении ошибки ErrorBoundary отрендерит Topline, подключенный через NPM. Стоит учесть, что в таком случае версия виджета будет задана явно через package.json.   

Итого  

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

Безусловно, у данного решения есть свои недостатки:  

  1. Клиент должен собираться Webpack версии 5.0.0 или старше. Другие сборщики не подойдут; 

  2. Сервер, который будет раздавать бандл, должен быть стабильным; 

  3. Нужно настроить кэшировние бандла; 

  4. Особо тщательно следить, чтобы обновления не принесли с собой breaking changes (при передаче props); 

  5. Расшерить типы для TS с помощью федераций не получится.  

Но несмотря на данные недостатки нами было принято решение использовать Module Federation для шеринга виджетов. Если говорить о Topline, то такой метод используется с весны 2021 года – на данный момент проблем с таким подходом не возникало, если не считать нескольких падений файлового хранилища, хранящего бандл – но на такой случай используется fallback.

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