- PVSM.RU - https://www.pvsm.ru -
Привет, меня зовут Стас, я работаю в команде Тинькофф Бизнеса. В прошлой статье мой коллега Ваня рассказал, как у нас устроена архитектура приложений [1]. Несколько раз Ваня упомянул некий Frame Manager, который служит оркестратором приложений, и сейчас я расскажу про него более подробно.
Тинькофф Бизнес предлагает решения для малого и среднего бизнеса: зарплатный проект, расчетно-кассовое обслуживание, конструктор документов и еще порядка 20 других продуктов.
Все это реализовано в приложениях. Эти приложения разрабатываются отдельными командами и имеют свои релизные циклы. А еще все эти приложения работают с единой авторизацией, содержат общую часть бизнес-логики, вынесенную в отдельную библиотеку, и используют общие UI-компоненты.
Типичное приложение Тинькофф Бизнеса выглядело примерно так:
Вверху — шапка с навигацией по приложению, а справа — сайдбар с навигацией по продуктам.
Тогда идея микрофронтенда еще не была такой популярной, но мы уже двигались в этом направлении: сайдбар представлял собой отдельное Angular-приложение. Основное приложение загружало сайдбар в iframe, что позволяло релизить приложения независимо.
Были у этого подхода и минусы: при переходе между продуктами приходилось ждать полной загрузки страницы с двумя Angular-приложениями. А из-за того, что большинство приложений используют одни и те же запросы к API бэкенда, пользователям приходилось ждать, пока они повторно отработают.
Мы жили с такой архитектурой, пока не появилась глобальная задача для всех приложений — редизайн. Тогда пришла идея: а почему бы не сделать своего рода инверсию контроля и вместо того, чтобы приложения загружали внутри себя сайдбар, сайдбар сам бы загружал приложения?
Это позволяло сохранить плюсы текущей архитектуры и избавляло от вышеназванных проблем (и приносило новые, ха-ха).
На начальном этапе мы создали прототип с минимальной функциональностью, необходимой для загрузки других приложений. На тестовом стенде был заведен отдельный домен. Поменялись роуты в nginx для статики приложений: раньше по путям /sme, /account, /salary и т. д. загружалась статика соответствующих приложений. Теперь же по всем путям отдавалась статика Frame Manager, а к роутам статики самих приложений добавился постфикс /static.
Чтобы стало понятнее, разберем пример: нужно загрузить приложение, находящееся на пути /some-app с каким-то роутом some-route. Отбросив детали, посмотрим, какой процесс происходит при загрузке /some-app/some-route/:
В самих приложениях при этом понадобились существенные доработки. Поэтому мы форкнули master ветки приложений и добавили туда необходимые изменения, после чего подняли отдельные экземпляры самих приложений с внесенными изменениями.
Так мы перевели 4 приложения во Frame Manager и убедились, что решение рабочее. Предстоял перевод всех остальных приложений. И тут мы столкнулись с проблемой: одновременно поддерживать обычную версию и версию для работы с Frame Manager оказалось слишком дорого.
Нам приходилось постоянно обновлять новые версии приложений на каждое изменение master’a старых версий, разрешать появляющиеся конфликты, часто ломалась уже существующая функциональность, затраты на регресс-тестирование увеличились почти вдвое — все это отнимало слишком много времени. Было понятно, что нужно новое решение.
Если бы одна версия приложения могла работать и с сайдбаром, и с Frame Manager, это избавило бы нас от многих проблем. Давайте посмотрим, что можно сделать.
Прежде всего нужно как-то определять, во Frame Manager ли запущено приложение. Сделать это довольно просто: нужно сравнить ссылки window.top и window.self. Если они окажутся не равны — значит, мы во фрейме, то есть во Frame Manager! Но, если есть приложения, которые по умолчанию открываются в iframe, нужно добавить дополнительную логику. Так, у нас было приложение-виджет, которое изначально открывалось во фрейме и стало считать, что оно всегда находится во Frame Manager’e, из-за чего ломалось в старом режиме.
Теперь рассмотрим подробнее, какие изменения необходимы в приложениях и как можно поддерживать работу в двух режимах:
Все это рабочие решения, но в них нет достаточной гибкости. Добавились новые ветки с логикой, которую также нужно поддерживать в разных местах. Да и в целом все выглядит переусложненной и достаточно неустойчивой конструкцией.
Тогда появилась идея немного хакнуть процесс загрузки index.html приложения. Вместо того чтобы загружать приложение в iframe, указывая атрибут src, можно сделать xhr-запрос за index.html, получить страницу в текстовом виде, обработать ее и загрузить в iframe. Это даст полный контроль над загружаемым приложением: позволит определять base href, удалять ненужные скрипты, патчить стили, переопределять переменные и многое другое!
Да, mokey patching не приветствуется среди разработчиков и считается плохой практикой, но если уж команда Angular его использует в библиотеке zone.js, чем мы хуже? Могут возникнуть сомнения насчет производительности: парсинг html выглядит дорогой операцией. Но, как правило, начальная страница Angular-приложения не превышает 50 строк, а во всех браузерах (даже в IE 10!) есть удобный api DOMParser [2], позволяющий из строки получить DOM.
Давайте посмотрим, что делает Frame Manager в процессе загрузки приложения (сам Frame Manager уже загружен):
Таким образом, из вышеперечисленных шести необходимых изменений в логике только первое (синхронизация url) нужно реализовывать внутри приложения, все остальное берет на себя Frame Manager!
Полностью изменили внешний вид приложения, практически не внося изменений в код самого приложения.
Получили возможность переопределять или добавлять глобальные переменные и стили.
export const business = {
'sidebar.b-main__sidebar': {
display: 'none'
},
'.b-main': {
'margin-left': '260',
position: 'relative',
display: 'block',
width: '1104px',
'min-height': '100vh',
margin: '0 auto'
}
};
{
id: 'products',
name: 'Все продукты',
icon: 'products',
frameSupported: true,
applications: [
{
id: 'products',
path: '/products',
apiPrefix: '/products',
hasMenuConfig: true,
dynamicCompanyChange: true,
}
]
}
При этом конфиги лежат в репозитории, отдельном от Frame Manager, что позволяет менять некоторые параметры работы приложений безрелизно.
Также создали бесшовные переходы между приложениями, вынесли авторизацию во Frame Manager. Добились того, что благодаря шарингу данных между Frame Manager и приложениями не делаются лишние запросы.
Не обошлось и без проблем: некоторые chrome-плагины (КриптоПро, redux devtools) перестали работать в загружаемом приложении, так как при взаимодействии терялась ссылка на window. Понадобились дополнительные доработки.
В итоге в конце 2019 года мы успешно перевели все приложения на Frame Manager, а сайдбар канул в Лету. Но работа над Frame Manager продолжалась, и возник новый вопрос: можно ли как-то еще улучшить и оптимизировать работу фронтенда в Тинькофф Бизнесе? Оказалось, что можно! Но об этом — в следующей статье.
Автор: Петров Станислав
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/frontend/357250
Ссылки в тексте:
[1] как у нас устроена архитектура приложений: https://habr.com/ru/company/tinkoff/blog/517230/
[2] DOMParser: https://developer.mozilla.org/ru/docs/Web/API/DOMParser
[3] Источник: https://habr.com/ru/post/520476/?utm_source=habrahabr&utm_medium=rss&utm_campaign=520476
Нажмите здесь для печати.