Привет, меня зовут Ваня, недавно я выступил на CodeFest 11, где рассказал про путь Тинькофф Бизнеса на фронтенде от одного приложения к сотне. Но так как в ИT очень быстро все меняется, а ждать запись еще долго, сейчас я тезисно расскажу о нашем шестилетнем путешествии в дивный мир микрофронтенда!
Мою статью можно разбить на две части. В первой части вас ждет история развития через призму бизнеса. А во второй — рассказ о том, как мы адаптировались к новым вызовам.
Этапы развития
Одно приложение на AngularJS в 2014—2015 годах.
Миграция на Angular2.
Утяжеление десяти приложений новой функциональностью.
Переход к микросервисам и разбиение на 100 приложений.
На дворе начало 2015 года. К нам приходит бизнес и говорит: «Мы хотим сделать зарплатный проект! Посмотрите, что есть сейчас на рынке по технологиям, и сделайте». Выбираем AngularJS, быстро создаем приложение. Спустя некоторое время аппетиты вырастают, мы создаем еще два сервиса. На этот момент фронтенд-приложения никак не взаимодействуют друг с другом.
Компания растет, мы доходим до десяти приложений в 2017 году. Команды еще не так сильно разрослись, но уже чувствуется локализация некоторой экспертизы. Для шаринга информации выделяется особая роль — «архитектор». С одной стороны, это самый технически прокачанный человек, с другой — евангелист наших подходов, который на одном языке общается как с бизнесом, так и с новичком в компании.
В 2017—2018 годах мы подумали, что уже хватит отдельных репозиториев, и стали добавлять фичи в существующие проекты и репозитории вместо создания новых.
В одном из проектов у нас было пять фронтенд-команд, в каждой по 3—5 человек, то есть в самый лучший момент в одном проекте работали 25 фронтендеров! Иногда было действительно больно: ты вот-вот замержишь свою задачку, но нет! Перед тобой кто-то успевает и все твои пайплайны начинают проходить заново! До сих пор мне не по себе от этих воспоминаний.
В какой-то момент мы осознали, что сборка приложения занимает уже полчаса и будет только расти, и решили распиливать наши монолиты на микросервисы.
Вот так быстро и пролетели шесть лет эволюции наших подходов. Теперь взглянем на наш путь через призму своих решений для микрофронтенда.
Сайдбар
Первые три приложения мы подружили между собой с помощью сайдбара.
В каждое приложение он встраивался с помощью ссылки на скрипт, который загружал на клиент полноценное приложение. Сайдбар отвечал за авторизацию, продукты клиента и текущий роутинг страницы, мог отправлять уведомления и загружал мессенджер на страницу. Как мы видим, довольно много возможностей у одного сервиса.
По технической части это iframe со всеми плюсами и минусами, о которых довольно подробно расписано в докладе Яндекса. Но больше всего нам не нравилась перезагрузка страницы на каждую смену продукта. Это мешало переиспользованию состояния клиента, требовало каждый раз обращаться к бекенду и добавляло некрасивые «мерцания» страницы при переходах.
Frame Manager
Именно рваные переходы мы убрали с появлением Frame Manager'а (далее буду называть его ФМ).
В отличие от сайдбара, который встраивался в приложение с помощью iframe, ФМ находился на странице всегда и сам встраивал в себя приложения.
Для клиента ФМ так же не заметен, как и сайдбар, но для нас он выполняет уже больше функций. Кроме рейтинга, списка продуктов и авторизации он может передавать состояние между приложениями, например через глобальный window. Пользователь больше не замечает, что ходит между несколькими отдельными приложениями, так как верхняя часть у него никуда не пропадает и визуально весь процесс выглядит как подгрузка контента на одну страницу.
В плане интеграции приложения тоже все поменялось:
Раньше приложению-клиенту достаточно было подключить необходимый скрипт к себе в index.html.
Теперь все приложения ФМа хранятся в отдельной конфигурации и используются как единый источник правды.
Минус этого подхода — мы все равно остались с iframe, который нам не особо нравился из-за особенностей работы с ним.
Однажды через поддержку к нам обратились пользователи с ситуацией: «Раньше у меня работал плагин для Google Chrome, а с недавнего времени именно на вашем сайте перестал. Почините, пожалуйста!» Обычно на такие просьбы не реагируют: пользователь что-то себе установил — пусть сам и разбирается. Но только не в нашей компании. Команда долго изучала вопрос, смотрела, какое окружение у клиента, версия браузера и все-все, но ответа так и не было. В итоге мы полностью повторили окружение, загрузили себе плагины и путем дебагинга установили, что данный плагин не работает, если у iframe динамически менять атрибут src или пересоздавать фрейм. К сожалению, мы так и не смогли исправить такое поведение, поскольку на этой концепции построено все взаимодействие ФМ и дочерних приложений.
Бесфрейм-менеджер
Однажды мы собрались и подумали: «Несколько лет страдаем от iframe. Как перестать страдать? Давайте просто уберем его!» Сказано — сделано. Так и появился бесфрейм-менеджер — с фантазией у нас, конечно, не фонтан ;-)
Ключевые отличия от предыдущей версии — самописная изоляция и работа с микрофронтендом вместо фрейма. На мой взгляд, лучше всего мотивацию создания отражает слайд из моей презентации:
В решении — три составляющие:
Webpack-плагин — основа нашего решения, подробнее о которой можно прочитать в статье Игоря.
Angular builder — обвязка для настройки и запуска плагина.
Angular schematics — скрипт для упрощения работы с файловой структурой с помощью AST.
В 2021 году плагин становится менее актуальным, потому что вышел Webpack 5 с Module Federation, но напомню, что мы вели разработку в 2018 году, а Angular стал поддерживать последнюю версию вебпака лишь с двенадцатой версии, которая вышла 12 мая 2021 года. Мы пока не уверены, сможет ли MF заменить наше решение, и изучаем комбинацию подходов.
Что же касается других решений, на которые можно было перейти для отказа от iframe, то это Single SPA. Он всем хорош и очень популярен, но в плане Angular есть небольшой дисклеймер.
Мы понимали, что глобально менять концепцию фреймворка нам никто не даст, потому решили доделать имеющийся.
Что же касается Angular builder и schematics, то они нужны, чтобы разработчики, которые будут интегрировать наше решение к себе, не выполняли километровую инструкцию, а просто написали в консоли:
ng update @scripts/deframing
И вся магия подключения произойдет у них на глазах, но не потребует никакого ручного вмешательства. Подробнее с работой билдеров и схематиков можно ознакомиться в классной статье.
Тестирование
Для нас важным моментом является автоматическое тестирование, тем более в проекте, от которого зависят все остальные команды. Путем проб и ошибок мы пришли к такому разделению тестового покрытия:
Можно прогонять тесты совместно с локальным ФМом. Так разработчики всегда могут быть уверены, что на текущей продовой сборке все работает и выглядит так, как и задумывалось.
Сам ФМ определяет несколько жизненно важных процессов, работоспособность которых гарантирует при любых условиях: это авторизация, роутинг, работа с данными приложений. Для этого создаются приложения-стабы (stub), суть которых — подключиться к ФМу и выполнить одну из вышеперечисленных функций. То есть на каждое изменение кодовой базы ФМа будет гарантированно работать эта функция.
Ну и как же обойтись без описания багов, которые мы встретили на своем пути. Их тоже можно поделить глобально на две группы: накопление стилей и сторонние библиотеки.
Накопление стилей — пользователь «гуляет» между приложениями, и у него накапливается состояние. Допустим, один из разработчиков написал:
.my-pretty-header {
display: none;
}
Если у кого-то из следующих приложений есть такое же название класса, этот стиль применится так же!
Пример: диалог решил спрятаться под меню, чтобы пользователь не догадался, что от него требуется:
Этот тип багов мы решили путем префикса по id приложения для всех стилей, чтобы они не имели глобальную видимость.
Сторонние библиотеки — если на одной странице два и более приложения используют библиотеку, которая на старте создает новый инстанс, то получается такая картина:
То есть библиотека пытается дважды запуститься и второй сервис затирает первый, что ломает поведение обоих. Это мы исправили путем небольших доработок библиотек.
Microzord
Вот мы и прошли шесть лет технического развития нашего решения. И что может быть лучше, чем поделиться этим опытом с сообществом? Все наработки будут публиковаться под npm scope @microzord
с открытым кодом на Гитхабе.
В планах — предоставить клиент не только для Angular, но и для работы с другими фреймворками. Сейчас лишь небольшая часть вынесена на Гитхаб, но будьте уверены, ребята не заставят себя ждать и в одной из следующих статей расскажут о гитхабе поподробнее.