Русский
Русский
English
Статистика
Реклама

Микрофронтенды

Задай вопрос Дэну Абрамову программа HolyJS в двух вариантах

05.11.2020 12:07:06 | Автор: admin


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


До HolyJS осталось меньше месяца, её программа сформирована, и мы решили рассказать вам о ней обоими способами сразу. Для тех, кому важна информативность, под катом есть официальные описания всех докладов. А для тех, кому хочется неформальнее и аналитичнее, добавили также видеозапись нашего youtube-шоу Тяжёлое утро с HolyJS: там как раз участники ПК разбираются в более свободной форме (вплоть до закадрового смеха).


Воркшопы и фреймворки, Дэн Абрамов и Виталий Фридман всё это ниже:


Оглавление



Разбор программы от ПК



Воркшопы


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


Получаем формы правильно: От флажков до выпадающих списков, Виталий Фридман


Чем хороша тема: Фронтендеры привыкли фигачить формы. Одна на завтрак, три на обед и баги по формам на ужин. Но правильно ли их делают? Как собрать в голове ментальную картину хорошей формы? Ответы есть у Виталия, который обладает огромнейшей экспертизой в области интерфейсов и их работы.
Чем ценен спикер: Виталий человек, который не нуждается в представлении. Он известный перфекционист и адвокат современного веба. Он отличается вниманием к каждой детали и в каждом своём докладе делает мир фронтенда чуточку лучше.
Кому будет полезно: если вы хоть раз верстали формы и у вас зачесалось при этом а будет ли эта форма эффективной?, а что можно было бы улучшить в ней?, если у вас хотя бы раз возникал немой вопрос какого черта тут происходит?, когда вы заполняли очередную форму на сайте то этот воркшоп для вас. Разберёмся, попробуем, потрогаем.




Сборка мелкого движка для 2D-игр на JS с использованием общеизвестных мелких библиотек, Иван Попелышев


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


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


В процессе воркшопа будут использованы CodeSandbox, PixiJS, p2, Tiled и мелкие сниппеты для интеграции. Фокус будет на архитектуре, то есть на том, как всё это связать и подготовить для месячной разработки игры.




Хватит использовать консоль для тестирования UI-компонентов, Дмитрий Коваленко


Мы привыкли к тому, что для того, чтобы протестировать фронтенд, нужен jsdom. Jest стал стандартом тестирования UI-компонентов. Но нормально ли то, что мы пытаемся тестировать UI в окружении Node.js? Доклад о том, как в Cypress.io пытаются перевернуть подход к тестированию компонентов.


Чем хороша тема: Тема тестирования не вполне раскрыта в современной JS-разработке. И люди либо не тестируют свой код, либо делают это не всегда правильно и оптимально. Спикер выдает аргументированное мнение, идущее вразрез с принятым в большинстве компаний подходом, который оправдывается пирамидой тестирования.
Кому будет полезно: Любому разработчику, который работает с UI. Джуны получат опыт тестирования визуальных компонентов (и не только), а люди с опытом смогут поставить под вопрос те методы тестирования, которые они используют ежедневно. Ну или задумаются о том, почему они не используют то, что уже здесь и просто.




Фреймворки


Интервью с Дэном Абрамовым, интервьюеры: Наталия Теплухина, Наталия Короткова


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


Что бы вы хотели узнать у Дэна? Присылайте нам свой вопрос с помощью этой формы.




SvelteJS under the hood, Павел Малышев


SvelteJS современный компилируемый JS-фреймворк, который наделал много шума в 2019 году, стал наиболее интересным фреймворком по версии State of JS и продолжает набирать популярность. В то же время, вокруг него сложилось много споров и противоречий, разночтений и просто слухов.


Действительно ли это радикально новый подход? Является ли SvelteJS фреймворком или это все-таки компилятор? Исчезает ли он на самом деле и где там магия? Как он вообще работает и при чем тут кибернетическое улучшение веб-приложений?


Павел предлагает заглянуть под капот этого интереснейшего фреймворка и попробовать разобраться.




Fully zone-less High-performance Angular applications in post IVY, Michael Hladky


Рассмотрим, как в Angular устроен механизм обнаружения изменений, и поймём, почему zone.js ваш злейший враг. Разберёмся с template bindings, рендерингом компонентов, и где в вопросах производительности приходится платить наибольшую цену. Как минимум, вы научитесь определять блокирующие UI (и избегать их), анализируя статистику flame charts. А как максимум, сможете в итоге добиться производительности приложения без зон, при этом на самом деле используя их!


Кому будет полезно: Всем, кто хочет глубоко разбираться в производительности (не только Angular)
Почему здесь и сейчас: Докладов о производительности немного




Mint programming language for writing single page applications, Gusztv Szikszai


Хотите узнать, что будет, если скрестить Elm и React? Как подружить функциональную разработку с тем, что делает команда React? Тогда вам сюда.


Чем ценен спикер: Доклад от создателя языка, который создал именно язык, а не просто фреймворк с высокоуровневыми обертками.
Кому будет полезно: Тем, кто хочет посмотреть на альтернативы JavaScript на фронте, и тем, кто хотел посмотреть на функциональный подход, но руки не доходили, потому что Хаскель это не практично.




Микрофронтенды


Architecting complex JavaScript (frontend) setups for large scale enterprise projects, Natalia Venditto


В этом докладе Наталия обсудит те вопросы, которыми надо задаваться каждому фронтенд-архитектору, когда он определяется с технологиями и архитектурными паттернами для крупных энтерпрайзных приложений. Она глубоко рассмотрит последние тренды вроде микрофронтендов и module federation, облачного и статического пре-рендеринга, поговорит о кроссбраузерной и кроссустройственной поддержке, об оптимизации производительности и Core Web Vitals.


Чем ценен спикер: Они в компании мигрировали проект на эти рельсы
Кому будет полезно: Тем, у кого есть большой проект на фронте и кто хочет разбить его на микрофронтенды.
Почему здесь и сейчас: Со стороны сборки мы ещё не заходили.




Microfrontends на React вместе с Kubernetes, Иван Затравкин


В этом докладе мы обсудим, что такое микрофронтенды, какие проблемы они решают, какие плюсы и минусы у этого подхода. Затем поговорим о Kubernetes и как это может быть полезно фронтенд-разработчику. В завершение посмотрим, как это всё работает вживую на production-ready коде.


Доклад призван дать практические навыки использования микрофронтендов и Configuration as a Code в отношении фронтенд-разработки.


Чем хороша тема: Микрофронтенды тренд 2020 года, в русскоязычном комьюнити мало докладов на эту тему. И, как правило, такие доклады не раскрывают ошибок и проблем, просто хайпят. А Иван решает реальные проблемы.
Кому будет полезно: Тем, кто хочет микрофронтенды, но не знает, как.




Микрофронтенды, module federation, Webpack 5, Павел Черторогов


Павел расскажет и покажет, как работает module federation в Webpack 5. Расскажет про то, как Zack Jackson и Tobias Koppers проделали титаническую работу, чтобы предложить достойный стандарт для микрофронтендов.


Чем ценен спикер: Павел обычно рассказывает про GraphQL. Но мимо Module Federation, который, по его мнению, сильно повлияет на индустрию корпоративного фронтенда, он просто не смог пройти мимо.
Чем хороша тема: С середины 2020 года Павел исследует вопрос того, как объединить разрозненные NextJS-приложения на разных поддоменах (админки различных сервисов) в один большой личный кабинет с единой шапкой и меню. Чтобы при переходе между сервисами не было перезагрузки страницы в браузере. При этом, чтобы разработчики сервисов могли влиять на работу меню и шапки из своих приложений, добавляя свои элементы и логику. Разделение ответственности, независимые деплои уже давно есть, теперь надо все это как-то красиво склеить. И оказывается, эта тема не такая простая, как кажется на первый взгляд. Просмотрено куча инструментов, сделан анализ, найдено решение. И спрятать это всё дело в тумбочку было бы кощунством.
Кому будет полезно: Этот доклад будет интересен тем, кто хочет собрать несколько разрозненных приложений в один SPA. Ну или разбить большой монолитный SPA на несколько небольших. Ох уж эти инженеры, сперва мучаются, что-то разбивают, а потом это самое разбитое обратно как-то хитро склеивают. Ненормальные Если вам интересно, как, а главное, зачем инженеры занимаются этой ерундой, то обязательно приходите посмотреть и послушать про микрофронтенды.




One logic to rule them all, from clot to wire, Владимир Минкин


Презентация концепции Strings API с библиотекой Wire для создания веб и мобильных приложений, которые повторно используют бизнес-логику в языке Dart.


Цель этого доклада: продвинуть идеи создания программных систем, состоящих из плагинов отдельных компонентов и блоков, которые можно тестировать индивидуально, визуально и в модульных тестах. Разделение ответственности это не новая идея и того же можно добиться с помощью уже существующих инструментов. Разница с Wire заключается в том, что он предоставляет простой и семантически красивый API с четким разделением задач на уровне API-библиотеки: общение в одном месте, данные в другом. В докладе будет уделено внимание архитектуре систем визуального ПО и тому, что всё это MVC, а также архитектуре Flux.




Стандарты


Comprehending standards notation for JS, Leo Balter


Чем ценен спикер: Лео известен своей активностью в TC39 и проектами вроде test262. Его работа над языковыми стандартами JavaScript помогает всем JS-разработчикам писать код лучше, но особенно важно, что его работа над интернационализацией позволяет разработчикам делать инструменты и интерфейсы, работающие без лингвистических и культурных границ.


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


Кому будет полезно: Этот доклад будет интересен и полезен самым разным JavaScript-разработчикам. Кому-то он просто поможет понять, как разрабатываются языковые фичи, какие мысли, идеи и усилия сопровождают этот процесс. А кто-то зайдёт дальше, и для него доклад окажется стартовой точкой, чтобы самому начать участвовать в улучшении языка.




Standardizing JavaScript decorators in TC39, Daniel Ehrenberg


В этом докладе Дэниэл объяснит, что представляет собой TC39 и как они работают. Посмотрим на некоторые недавние языковые пропоузалы вроде Temporal, разберём, как декораторы проходили через процесс TC39 (в том числе как и почему они менялись). Вы тоже можете помочь TC39 развивать JavaScript.


Чем ценен спикер: Дэниэл занимается этим стандартом, к тому же он бывший председатель, эксперт TC39.
Чем хороша тема: Декораторы важная часть JS, стандарта еще нет, а уже много всего на этом завязано из-за удобства. Первая версия стандарта про декоратор была провальной, и ее не приняли.
Кому будет полезно: Тем, кто интересуется стандартами и будущим языка.




WebAuthn: Theory and practice, Martin Splitt


Точная тема этого доклада сейчас ещё не сформулирована (как только это произойдёт, обновим описание на сайте. Но речь пойдёт об аутентификации вообще и Web Auth в частности.


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


Чем ценен спикер: Мартин developer advocate из Google, известный как отличный спикер, его предыдущие доклады на HolyJS получали высокие оценки зрителей
Чем хороша тема: Web Auth это новое API, помогающее людям использовать простую аутентификацию. Об этом пока что немного докладов
Кому будет полезно: Всем, кто использует аутентификацию




Wonderful world of new Web API, Thomas Steiner


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


Томас developer advocate в Google, который стремится сделать веб лучше благодаря стандартизации, наработке и распространению лучших практик, а также исследованиям. Он ведёт блог и твиттер @tomayac.




Рендеринг


Автоматическая виртуализация рендеринга произвольной верстки, Дмитрий Карловский


Рендерить всё это слишком медленно. Подстраиваться под ограничения виртуального скролла сложно.


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


Чем ценен спикер: Спикер часто задумывается о практических вещах, которые многие разработчики часто могут упускать и использовать хайповые решения для костылей.
Чем хороша тема: Вы когда-нибудь рендерили списки? А бесконечные списки? Открывали ли вы merge request на GitHub или GitLab с сотнями комментариев? Пытались участвовать в обсуждении на Хабре, где комментариев хорошо за 300? В этих случаях перед разработчиками встает вопрос как все отрендерить, чтобы ничего не отвалилось (например, скролл в рандомную точку). Дима разберет различные стратегии, опишет проблемы современных решений и предложит нестандартный способ по реальному улучшению ситуации.
Кому будет полезно: Всем, у кого на работе есть длинные списки.




React Reconciler: Как написать собственный рендерер, Ярослав Лосев


Что такое реконсиляция в React и какой путь проходит компонент от кода до отрисовки на экран? Какие рендереры уже существуют и как написать свой собственный на примере отрисовки React-компонентов в Figma с использованием React Reconciler.


Доклад позволяет практикующим разработчикам глубже окунуться в то, как устроен React и его архитектура.


Чем ценен спикер: Ярослав один из основных контрибьторов react-figma, пишет свои конфиги, столкнулся с кучей нюансов такой работы, так как либа опенсорсная и доступная для всех.
Кому будет полезно: Разработчикам, которые используют React в повседневных задачах. Доклад даст огромное понимание о том, что происходит под капотом и как управлять рендером.




Архитектура


Алгоритмы консенсуса. При чем тут Node.js?, Андрей Печкуров


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


Наконец, окончательно напуганные некоторыми популярными алгоритмами консенсуса, мы на примере одного образовательного проекта порассуждаем на тему того, что нужно, чтобы написать производительное линеаризуемое хранилище пар ключ-значение на Node.js.


Доклад должен быть полезен всем Node.js-разработчикам, независимо от опыта.


Кому будет полезно: Будущим архитекторам и тем, кто не знает, что такое алгоритм консенсуса.
Почему здесь и сейчас: На JS-конференциях о таком обычно не рассказывают, фундаментальная тема для расширения профессионального кругозора.




Перформанс


Core Web Vitals: Theory and practice, Elizabeth Sweeny, Иван Акулов


Ура, веб-производительность! В этом докладе Элизабет и Иван глубоко погрузятся в теорию и практику Core Web Vitals:


Что это такое, почему они имеют значение и как их измерять
Как Lighthouse вычисляет оценку, и какую роль в этом играют CWV
И как оптимизировать Core Web Vitals на практике (на примере реального сайта)


Чем ценен спикер: Она Product Manager веб-платформы в Google
Чем хороша тема: Сейчас Web Vitals и метрики это тренд
Кому будет полезно: Каждому фронтендеру, которого волнуют метрики




Автоматизация


Rise of the robots, Theodore Vorillas


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


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


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




Babel: A refactoring tool, Nicol Ribaudo



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




Build tools


Модульный JavaScript: Динамическое разрешение зависимостей, Юрий Караджов


Чем ценен спикер: Видеть недостатки в популярных решениях это не редкость, а вот предлагать оригинальные рабочие решения это уже незаурядно. Опыт есть не только в разработке инструмента, но и в его внедрении в рабочие процессы растущей компании. А до этого эти идеи внедрялись в команде Apple
Чем хороша тема: Сейчас хватает поделок, связанных со сборкой проектов, но очень немногие из них похожи на production-ready решения. Здесь рассказ про инструмент, который закрывает недостатки существующих проектов на базе webpack и предлагает несколько другой подход к работе с зависимостями
Кому будет полезно: Если вам нравится webpack и вы хотите лучше узнать о кейсах, когда он не так хорош, как все считают. Если вам НЕ нравится webpack и вы хотите узнать про альтернативу
Почему здесь и сейчас: Проектов подобного рода (крупных) всего два, ни один не освещен толком в сообществе. Этот рассказ от создателя, фактически презентация на русскоязычную аудиторию




Тестирование


Хватит использовать консоль для тестирования компонентов, Дмитрий Коваленко


Чем хороша тема: Тема тестирования недораскрыта в современной JS-разработке. И люди либо не тестируют свой код, либо делают это не всегда правильно и оптимально. Спикер выдает аргументированное мнение, которое идет вразрез с принятым в большинстве компаний подходом, который оправдывается пирамидой тестирования
Чем ценен спикер: По теме у Дмитрия явно свой оформленный взгляд, достаточно посмотреть на его веселые баталии с Ильей Климовым
Кому будет полезно: Любому разработчику, который работает с UI. Джуны получат опыт тестирования визуальных компонентов (и не только), а люди с опытом смогут поставить под вопрос те методы тестирования, которые они используют ежедневно. Ну или задумаются о том, почему они не используют то, что уже здесь и просто
Почему здесь и сейчас: Свежий взгляд на проблему и опыт от разработчика инструментов, для решения этой проблемы, помножены на смелость заявить отличную от распространенной точку зрения




Case study


Как разработать свой собственный формат баннера на примере Lamoda, Роман Пятаков


Чем хороша тема: У спикера богатый опыт в разработке баннерки, наступления на грабли и решения их проблем. Спикер разберет весь путь обновления баннеров, сбора проблем и их решений в Lamoda и также даст качественную оценку текущего решения.
Чем ценен спикер: Спикер непосредственно участвовал во всем процессе и сможет дать информацию из первых рук по этому case study
Кому будет полезно: Если вашем сайте есть баннеры, то доклад будет полезен
Почему здесь и сейчас: Опыт одной из крупных компаний в рунете.




И что дальше?


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


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

Подробнее..

Микрофронтенды разделяй и властвуй

14.04.2021 16:05:26 | Автор: admin


Всем привет! Меня зовут Аня, я фронтенд-разработчик в Delivery Club. Хочу рассказать про использование микрофронтендов. Поговорим о том, что же это за зверь такой микрофронтенд, почему мы решили использовать этот подход в своих проектах и с какими проблемами столкнулись при внедрении.

Для чего они нам понадобились


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

  • Сложно жить с монолитом. Быстро писать код мешали устаревание подходов, фреймворков и зависимостей, а также связанность логики.
  • Совместная разработка. Долго решать конфликты, противоречивость изменений.
  • Проблема с тестированием. Когда прилетали баги от других задач и команд, было непонятно, в чём причины.
  • Развёртывание было зависимое и блокирующее.

Поэтому нам нужна была возможность:

  • использовать любые инструменты и технологии, снижая риск устаревания;
  • разрабатывать и деплоить независимо;
  • изолировать реализации.

Устройство проекта


Для начала расскажу, как сейчас устроен наш проект.

  • Основное старое приложение на AngularJS, к которому мы планируем подключать новые микроприложения.
  • Dashboard-приложение на Angular 6, подключенное через iframe (но оно со временем разрослось и от описанных выше проблем не избавило). К нему подключаются приложения, здесь хранятся старые страницы.
  • Приложения на VueJS, которые используют самописную библиотеку компонентов на VueJS.





Мы поняли, что ограничения тормозят развитие проекта. Поэтому сформулировали возможные пути:

  • Разделение приложения на страницы по маршрутам.
  • iframe.
  • Микрофронтенды.

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

Что такое микрофронтенды


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


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

Проблемы внедрения микрофронтендов


1. Ещё один iframe? Может, уже хватит?


К великому разочарованию, наше dashboard-приложение открывается внутри iframe (исторически так сложилось), и нам очень не хотелось делать один iframe внутри другого. Однако это был запасной план. Если вдруг что-то пойдёт не так, то просто заворачиваем микрофронтенд в iframe и готово рабочее приложение.

Мы видели несколько недостатков:

  • Неудобная навигация. Каждый раз для редиректа на внешнюю ссылку нужно использовать window.postMessage.
  • Сложно верстать в iframe.

К счастью, нам удалось этого всего этого избежать, и микрофрентенд мы подключили как веб-компонент с shadow dom: <review-ui-app></review-ui-app>. Такое решение выгодно с точки зрения изоляции кода и стилей. Веб-компонент мы сделали с помощью модифицированного vue-web-component-wrapper. Почитать подробнее о нём можно здесь.

Что мы сделали:

  1. Написали скрипт, который добавляет ссылку на сборку микрофронтенда в разделе head страницы при переходе на соответствующий маршрут.
  2. Добавили конфигурацию для микрофронтенда.
  3. Добавили в window.customElements тег review-ui-app.
  4. Подключили review-ui-app в dashboard-приложение.

Так мы сразу убили несколько зайцев. Во-первых, приложение представляет собой кастомный тег, как мы привыкли компонент. Во-вторых, кастомный тег принимает данные как свойства, следит за ними и выбрасывает события, которые слушает обёртка. Ну и в-третьих, избавились от iframe внутри iframe :)

2. А где стили?


Ещё одна неприятная проблема нас ждала дальше. Компоненты в микрофронтенде работали, только вот стили не отображались. Мы придумали несколько решений:

  • Первое: импортировать все стили в один файл и передать его во vue-wrapper (но это слишком топорно и пришлось бы добавлять вручную каждый новый файл со стилями).
  • Второе: подключить стили с помощью CSS-модулей. Для этого пришлось подкрутить webcomponents-loader.js, чтобы он вшивал собранный CSS в shadow dom. Но это лучше, чем вручную добавлять новые CSS-файлы :)

3. Теперь про иконки забыли!


Затем мы подключили внутреннюю библиотеку, но в ней не отображались SVG.
С иконками нам пришлось повозиться подольше. Для их подключения нам пришлось сделать несколько итераций:

  1. Сначала мы попытались подрубить спрайт так же, как и стили, через appendChild. Они подключились, но всё равно не отображались.
  2. Затем мы решили подключить через sprite.mount(this.shadowRoot). Добавили в вебпаке в svg-sprite-loader опцию spriteModule: path.resolve(__dirname, './src/renderers/sprite.js). Внутри sprite.js экспортировали BrowserSprite, и иконки начали отображаться! Мы, счастливые, подумали, что победили, но не тут-то было. Да, иконки отображались, и мы даже выкатились с этой версией в прод. Но потом нашли один неприятный баг: иконки пропадали, если походить по вкладкам dashboard-приложения.
  3. Наконец, во vue-wrapper мы подключили DcIconComponent (библиотечный компонент, позволяющий работать с библиотечными иконками) и в нём подключили иконки из нашего проекта. Получили отображение без багов :)

4. Без авторизации никуда!


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

  • Токен с авторизацией передаём с помощью свойств веб-компонента.
  • С помощью AuthRequestInterceptor подключаем токен-запросы для API.
  • Используем токен, пока он не протухнет. После протухания ловим ошибку 401 и кидаем в dashboard-приложение событие обнови токен, пожалуйста (ошибка обрабатывается в AuthResponseInterceptor).
  • Dashboard-приложение обновляет токен. Следим за его изменением внутри main-сервиса, и когда токен обновился, заворачиваем его в промис и подписываемся на обновления токена в AuthResponseInterceptor.
  • Дождавшись обновления ещё раз повторяем упавший запрос, но уже с новым токеном.

5. Нас волнуют зависимости


Проблема выглядела так: с каждым подключённым микрофронтом тянется бандл. И сколько микрофронтов подключено, столько и бандлов подтянуто. Чтобы избежать этого, мы применили общие зависимости. Вот как мы это реализовали:

  • В микрофронтенд-приложении указываем в webpack.config.prod.js в разделе externals те зависимости, которые хотим вынести:

    module.exports = {externals: {vue: Vue},
    

    Здесь мы указываем, что под именем Vue в window можно будет найти зависимость vue.
  • В рамках оболочки (в нашем случаем в dashboard-приложении) выполняем npm install vue (и другие npm install-зависимости).
  • В dashboard-приложении импортируем все зависимости:

    import Vue from vue(window as any).Vue = Vue;
    
  • Получаем удовольствие.

6. Разные окружения


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

Решили мы это следующим образом:

  1. Добавили в микрофронтенд файл, в котором определяем конфигурацию для приложения в runtime браузера. Также добавили в Docker системный пакет, который предоставляет команду envsubst. Она подставляет значения в env.js, который тянет микрофронтенд-приложение, и эти переменные пишутся в window['${APP_NAME}_envConfig'].
  2. Добавили переменные окружения отдельно для прода и отдельно для тестового окружения.

Так мы решили несколько проблем:

  • настроили локальные моки (раньше приходилось вручную включать их локально);
  • настроили тестовое окружение без дополнительных ручных переключений на прод и обратно.

Выводы


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

Думаю, со временем всё больше проектов будут отказываться писать монолит и переходить на более универсальные подходы. Одним из таких подходов могут стать и микрофронтенды. Надеюсь, эта статья поможет кому-то в реализации :).
Подробнее..

Микрофронтенды и виджеты в 2021-м. Доклад Яндекса

07.05.2021 12:20:51 | Автор: admin
Давайте поговорим о микрофронтендах и о встраиваемых виджетах, которые, по сути, были предшественниками концепции микрофронтендов. В докладе я рассказал о способах встраивать виджеты на страницу, об их плюсах и минусах с точки зрения изоляции и производительности кода, а также о способах применять виджеты в микрофронтендной архитектуре.

Всем привет! Меня зовут Леша. Я хочу с вами сегодня обсудить немного перехайпленную тему микрофронтенды.

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

Микрофронтенды дальнейшее развитие этой идеи. Мы наше монолитное фронтенд-приложение также разделяем на независимые куски, независимые сервисы. Каждый сервис делается выделенной командой. Это может быть команда, у которой собственный фронтенд и бэкенд.

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

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

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

Я за время работы в компании тоже успел поработать над несколькими проектами, которые в целом находятся в концепции микрофронтендов. (...) Cейчас я занимаюсь разработкой видеоплеера, который вы уже видели на слайде. Это виджет, который воспроизводит видео и трансляции.

Евангелистом идеи микрофронтендов я совершенно не являюсь. У этой идеи, как и у всех, есть свои плюсы и минусы. Давайте мы с вами о них поговорим.

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

Какие у этой концепции проблемы? Она сильно усложняет код, дает дополнительные накладные расходы на интеграцию и взаимодействие виджетов в микрофронтендах между собой, накладывает требования по обратной совместимости чтобы API, через который виджеты общаются, при релизах не ломался и ваше приложение не развалилось. Свобода в технологическом стеке наверное, тоже своего рода минус. Думаю, вам не очень хотелось бы пользоваться сайтом, который для отрисовки одного кусочка грузит Angular, а для другого React, это будет работать не слишком быстро. Так что свобода это одновременно и плюс, и минус.

Зачем вам эту концепцию использовать? Я для себя на этот вопрос ответил двумя пунктами. Первый: у вас большое приложение и несколько независимых команд разработки.

Второй: вы делаете встраиваемые виджеты, которые работают не только в микрофронтенде, а еще встраиваются на ваши сайты или, например, на сайты партнеров.

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

Как технически реализовать микрофронтенды/виджеты?


declare const DoggyWidget: {    init: ({        container: HTMLElement,    }) => DoggyWidgetInstance;}declare interface DoggyWidgetInstance {    destroy(): void;    updateDoggy(): void;}

В качестве примера возьмем вот такой простенький виджет DoggyWidget, он лежит по ссылке на GitHub. Виджет рисует картинку и кнопочку. Картинка принимает размеры контейнера, куда вы виджет вставили, и показывает рандомную фотографию собаки. Кнопка при нажатии меняет эту фотографию на другую рандомную. У нашего виджета будет API, с помощью которого с ним можно будет как-то взаимодействовать.

Из чего он будет состоять? В первую очередь он будет декларировать глобальный namespace DoggyWidget, в котором будет фабрика и с помощью которого можно создать инстанс этого виджета. У инстанса будет два метода. Первый метод destroy, который при вызове удалит виджет со страницы и почистит всё, что он успел сделать с DOM-ом. Второй метод updateDoggy, который делает то же самое, что нажатие на кнопку, а именно меняет картинку.

Давайте подумаем, как такой виджет реализовать.

<script>


Первая идея в лоб: наш виджет будет отдельным скриптом.

class Widget {    constructor({ container }) {        this.container = container;        container.classList.add('doggy-widget');        this._renderImg();        this._renderBtn();        this.updateDoggy();    } }

Давайте инстанс виджета определим с помощью класса. У класса будет конструктор, который принимает конфиг. В конфиге есть контейнер, где виджет должен рисоваться. Мы на этот контейнер навесим className, вызовем два метода для отрисовки картинки и для отрисовки кнопки и вызовем updateDoggy, который поставит начальную картинку при инициализации виджета.

    _renderImg() {        this.img = document.createElement('img');        this.img.classList.add('doggy-widget__img');        this.img.alt = 'doggy';        this.container.appendChild(this.img);    }

Что будет делать renderImg? Он будет создавать тег img, навешивать на него className и аппендить его в контейнер.

    _renderBtn() {        this.btn = document.createElement('button');        this.btn.classList.add('doggy-widget__btn');        this.btn.addEventListener('click', () => this.updateDoggy());        this.container.appendChild(this.btn);        this.btn.innerText = 'New doggy!';    } 

renderBtn будет делать примерно то же самое, только он будет создавать не img, а кнопочку.

    updateDoggy() {        const { width, height } = this.container.getBoundingClientRect();        const src = `https://placedog.net/${width - 10}/${height - 10}?random=${Math.random()}`;        this.img.src = src;    }

И у нас еще есть публичный API. updateDoggy определяет параметры контейнера, куда мы вставили виджет, конструирует ссылку на изображение. Я здесь буду использовать сервис placedog.net, который подставляет рандомные плейсхолдеры с фотками собак. Метод src ставит тег img.

    destroy() {        this.container.innerHTML = '';        this.container.classList.remove('doggy-widget');    }

destroy будет очень простой он будет подчищать innerHTML у контейнера и снимать с него className, который мы поставили в конструкторе.

(() => {    class Widget {        ...    }    window.DoggyWidget = {        init(config) {            return new Widget(config);        }    }})();

Напишем код, с помощью которого виджет будет вставляться. Мы его содержимое обернем в IIFE, чтобы спрятать класс виджета в замыкание, и определим в нем глобальный namespace DoggyWidget, в namespace будет функция init фабрика, которая вернет нам инстанс виджета.

<script src="doggy-widget.js"></script><link rel="stylesheet" href="doggy-widget.css"><div id="widget-1"></div><div id="widget-2"></div><script>    const widget1 = DoggyWidget.init({         container: document.getElementById('widget-1'),    });    const widget2 = DoggyWidget.init({         container: document.getElementById('widget-2'),    });</script>

Как это все будет ставиться на страничку? Вот два файла: doggy-widget.js с JS-кодом, который мы разобрали, и doggy-wodget.css со стилями для виджета.

Мы заведем два div, и в каждый из них вставим виджет через DoggyWidget.init(), который мы тоже в doggy-widget.js описали.

Ссылка со слайда

Это все будет выглядеть так. У первого виджета будет updateDoggy.

Ссылка со слайда

Мы его вызовем. Он изменит нам фотографию.

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

Ссылка со слайда

        * {            font-family:         Arial, Helvetica, sans-serif !important;            font-size: 10px !important;        }

Представим, что мы наш виджет встроили на страничку, где находится вот такой CSS-код.

Ссылка со слайда

Что произойдет, когда мы отрисуем виджет? Очевидно, у него поедет верстка, потому что у нас есть глобальный CSS selector, который для всех элементов переопределяет font-family и font-size. Так что виджет не очень хорошо изолирован от окружающего его CSS-кода.

Вы скажете, что это вредительство и такого CSS никто не пишет.


Ссылка со слайда

<link rel="stylesheet"       href="bootstrap.min.css">*, ::after, ::before {    box-sizing: border-box;}

Окей, рассмотрим чуть более реальный пример. Мы встраиваемся на страничку, на которой используется Bootstrap, например. В Bootstrap есть такой код, который всем элементам задает box-sizing.

Предположим, мы наш виджет отрисуем на такой страничке:

Тогда у него чуть-чуть поедут размеры, потому что border переехал из-за box-sizing внутрь элемента у нас меняются размеры виджета. Не очень классно. Получается, что наш виджет подвержен влиянию окружающего его кода, чего мы в микрофронтендах хотим избежать.

Как этого можно избежать? Первый вариант: есть достаточно старый проект cleanslate.css.

<body>  <div class="blah">      <!-- general content is not affected -->      <div class="myContainer cleanslate">          <!-- this content will be reset -->      </div>  </div></body>

Это специальный CSS reset, который перезагружает стили не на всей страничке, а только на том div, где стоит класс cleanslate. Всё, что находится внутри cleanslate, будет переопределено, у него будут дефолтные зарезеченные стили.

Либо есть более современное решение, которое использует часть спецификаций веб-компонентов, а именно Shadow DOM.

Shadow DOM это такой способ отрисовать часть DOM-дерева изолированно и скрыто от других элементов на страничке. С помощью Shadow DOM рисуются встроенные в браузер контролы, например, input range. Если вы посмотрите на него в dev tools, там внутри в shadow root находится верстка, стилизованная с помощью CSS, который зашит в движок браузера.

    constructor({ container }) {        this.shadowRoot = container.attachShadow(            { mode: 'open' }        );        this.innerContainer = document.createElement('div');        this.innerContainer.classList.add('doggy-widget');        this.shadowRoot.appendChild(this.innerContainer);            }

Окей, попробуем заюзать Shadow DOM для нашего виджета. Что нам для этого нужно? В конструкторе мы приаттачим в контейнер shadowRoot, создадим еще один div, назовем его innerContainer и зааппендим его внутрь нашего shadowRoot.

    _renderImg() {                this.innerContainer.appendChild(this.img);    }    _renderBtn() {                this.innerContainer.appendChild(this.btn);    }

И нам потребуется немного переделать методы renderImg(), renderBtn(). Теперь мы будем картинку и кнопку складывать не в контейнер, который нам пришел, а в innerContainer, который мы уже положили внутрь shadowRoot.

    destroy() {                this.shadowRoot.innerHTML = '';    } 

Осталось еще немного поправить destroy. В destroy будем shadowRoot просто подчищать за собой.

Класс! Кажется, мы использовали Shadow DOM и смогли нашу верстку изолировать от другого кода.


Ссылка со слайда

В этом случае мы получим что-то такое у нас пропали все стили.


Что именно произошло? Изоляция, которую обеспечивает Shadow DOM, работает в обе стороны: она блокирует как вредоносные стили, которые нам не нужны, так и наши собственные стили, которые мы хотим добавить. Смотрите, link с doggy widget CSS остался снаружи shadowRoot, а верстка виджета находится внутри. Соответственно, правила, которые описаны снаружи, не влияют на то, что находится внутри shadowRoot.

     constructor() {                const link = document.createElement('link');        link.rel = 'stylesheet';        link.href = 'doggy-widget.css';        this.shadowRoot.appendChild(link);            }

<script src="doggy-widget.js"></script>

<link rel="stylesheet" href="doggy-widget.css">

Чтобы это полечить, нам нужно тег link класть внутрь shadowRoot. Сделать это очень просто. Создаем элемент link, ставим ему href и аппендим его внутрь shadowRoot. В коде вставки виджета на страницу отдельный CSS-файл нам уже будет не нужен, он будет подключаться в конструкторе виджета.

Ссылка со слайда

Это будет работать примерно так. По ссылочке пример с подключенным Bootstrap, где можно посмотреть, что наш виджет по верстке получилось изолировать.

Единственная проблема, которую вы можете заметить, если откроете dev tools: на каждую инициализацию виджета появился отдельный запрос за doggy-widget.css. Здесь вам нужно будет убедиться, что у вас корректно настроено кеширование, чтобы повторно не грузить этот файл вашим клиентам.

Вроде изоляцию мы полечили. Или не совсем? Давайте немножко поиграем в шарады.

Опытные разработчики поймут, что здесь зашифрован monkey-patching. Это техника, которая нам позволяет делать прототипное наследование JavaScript, а именно изменять стандартную библиотеку. Например, через это работают полифилы. Мы можем в старый браузер притащить метод, который появился в новой спецификации, чтобы писать код, используя новые спеки. Но monkey-patching позволяет как делать хорошие штуки, так и очень сильно всё ломать.

Расскажу пример, с которым мы столкнулись, когда я работал в рекламных технологиях.

var str = JSON.stringify(['haha'])> '["haha"]'JSON.parse(str)> ["haha"]

Был у нас примерно такой код. Мы стрингифаили массивчик. Очевидно, результат у этого выражения вот такой. И потом мы эту застрингифаенную строчку отправляли на наш бэкенд, где потом ее парсили.

Очевидно, если мы такую строку распарсим, то получим массив. Все хорошо.

var str = JSON.stringify(['haha'])> '"[\"haha\"]"'JSON.parse(str)> '["haha"]'

А вот на сайте одного из партнеров, куда мы этот виджет встраивали, мы видели такую картину.

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

Array.prototype.toJSON: () => Object

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

Array.prototype.toJSON = function () {    var c = [];    this.each(function (a) {        var b = Object.toJSON(a);        if (!Object.isUndefined(b))            c.push(b)    });    return '[' + c.join(', ') + ']'}

И как раз на этом сайте мы обнаружили такой код, внимание на предпоследнюю строку. В прототип массива добавлялся метод toJSON, который возвращал не сериализуемый объект, как должно быть по спеке, а строчку.

Код этот прилетел из старой библиотеки prototype.js, это такая либа эпохи раннего jQuery, которая занимается тем, что расширяет стандартную библиотеку JavaScript для появления удобных в использовании методов.

Мы, кстати, как потом выяснилось, не единственные, кто с такой проблемой столкнулся. На Stack Overflow есть обсуждение, где предлагается эту проблему пролечить таким страшненьким кодом:

var _json_stringify = JSON.stringify;JSON.stringify = function(value) {    var _array_tojson = Array.prototype.toJSON;    delete Array.prototype.toJSON;    var r=_json_stringify(value);    Array.prototype.toJSON = _array_tojson;    return r;};

Строго говоря, предлагается полечить monkey-patching еще одним monkey-patching, что не кажется очень хорошим решением.

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

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

Давайте попробуем сломать наш виджет, посмотреть, как такой мониторинг будет работать и что он нам даст.

    _renderImg() {        const img = document.createElement(img');        this.img = img;        img.classList.add('doggy-widget__img');        img.alt = 'doggy';        this.container.appendChild(this.img);         this.updateDoggy(img);    }

Если помните, у нас был метод renderImg, который отрисовывал картинку. Давайте мы его сломаем, а именно удалим третью строчку, которая img кладет в поле нашего класса.

Что произойдет? Начальная отрисовка у нас отработает.

Ссылка со слайда

А вот если мы нажмем на кнопочку, то увидим exception.

window.addEventListener('error', (e) => {    console.log('got error:', e.error);    e.preventDefault();});


Как этот exception можно поймать, обработать и залогировать? Что делают те сервисы, которые я показывал несколько слайдов назад? Есть глобальный ивент 'error', который срабатывает на объекте window. На него можно подписаться и получить из этого ивента объект ошибки, которая произошла и которую вы не отловили через try-catch. У ивента можно вызвать preventDefault, чтобы также скрыть красную ошибку в консольке и не пугать ваших пользователей, которые внезапно решили открыть devtools.

В нашем виджете это будет выглядеть так. При нажатии на кнопку будет срабатывать обработчик.

window.addEventListener('unhandledrejection', (e) => {    console.log('got promise reject:', e.reason);    e.preventDefault();});

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

Promise.reject(new Error('bla'))

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


window.addEventListener('error', (e) => {    console.log('got error:', e.error);    e.preventDefault();});

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

Так что независимые мониторинги при таком подходе мы не получаем.

Давайте подведем промежуточные итоги. Что нам дает использование независимых скриптов?

У нас есть минимум накладных расходов. Каждый отдельный элемент микрофронтенда, каждый виджет, это просто лишний скрипт. Кажется, менее накладно это сделать нельзя. Но при этом у нас плохая изоляция, мы научились изолировать верстку с помощью Shadow DOM, а JS мы изолировать не можем. И у нас нет хороших независимых мониторингов ошибок.

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

Тем не менее, эта идея активно используется. Например, один из популярных фреймворков для построения микрофронтендов single-spa как раз на ней, в общем-то, и построен.

Что делать, если нам это все не подходит и хочется больше изоляции? Здесь поможет старая технология iframe.

<iframe>


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

(() => {    window.DoggyWidget = {        init({ container }) {            const iframe = document.createElement('iframe');        }    }})();

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

(() => {    window.DoggyWidget = {        init({ container }) {            const iframe = document.createElement('iframe');            iframe.style.width = '100%';            iframe.style.height = '100%';            iframe.style.borderWidth = 0;            iframe.style.display = 'block';            iframe.src = 'https://some-url/doggy-widget.html';                    }    }})();

В фабрике init нашего виджета нам нужно будет создать iframe и повесить на него стили. Мы поставим width и height 100%, чтобы он полностью растягивался до размеров контейнера, куда его вставили. Мы переопределим ему display и поставим границу 0, потому что по дефолту браузеры рисуют border.

Внутри iframe загрузим документ, в котором будет рендериться наш виджет.

(() => {    window.DoggyWidget = {        init({ container }) {            const iframe = document.createElement(iframe');            iframe.style.width = '100%';            iframe.style.height = '100%';            iframe.style.borderWidth = 0;            iframe.style.display = 'block';            iframe.src = 'https://some-url/doggy-widget.html';            container.appendChild(iframe);                        ...        }    }})();

Осталось зааппендить этот iframe внутрь контейнера.


Ссылка со слайда

Все будет работать, виджет будет отрисовываться.

Вроде здорово. Мы использовали iframe, виджет в нем работает, не подвержен влиянию другого кода на страничке. У нас есть полная изоляция, независимые мониторинги внутри iframe.

declare const DoggyWidget: {    init: ({        container: HTMLElement,    }) => DoggyWidgetInstance;}declare interface DoggyWidgetInstance {    destroy(): void;    updateDoggy(): void;}

Но мы кое о чем забыли. У нашего виджета есть API. У инстанса есть destroy и updateDoggy. Давайте попробуем их реализовать.

destroy() {    this.container.innerHTML = '';}

destroy будет суперпростой. Нам нужно будет просто почистить контейнер, если вы не используете этого парня. В IE 11 и legacy Edge есть неприятный баг, связанный с тем, что контекст JS, который работает внутри фрейма, продолжает частично жить после удаления iframe из DOM. Что значит частично? В нем ломается стандартная библиотека, перестают, например, быть доступны объекты Date, Object, Array и прочее. Но асинхронный код, сет таймауты, сет интервалы, реакция на ивенты, которая там была, продолжают работать, и вы можете в ваших мониторингах в таком случае увидеть очень странные эксепшены из IE и legacy Edge о том, что у вас вдруг пропал Date, он стал undefined.

Чтобы это обойти, нам наш iframe предварительно перед удалением его из DOM нужно будет вот таким образом почистить. Тогда IE 11 и старый Edge корректно его задестроят и остановят весь JS-код, который внутри него выполнялся.

destroy() {    // чистим iframe для ie11 и legacy edge     this.iframe.src = '';    this.container.innerHTML = '';}


Ссылка со слайдов

Proof of concept destroy работает.

Что еще? У нас остался updateDoggy, для него нам нужно обновить картинку, которая рисуется внутри фрейма. Соответственно, сделать какое-то действие между нашим основным документом, отправить команду внутрь iframe. Здесь есть проблема. Если iframe загружается с другого хоста, браузер заблокирует любое взаимодействие с window внутри фрейма и вы получите примерно такую ошибку.

Как же все-таки можно взаимодействовать? Для взаимодействия нужно использовать postMessage. Это API, который позволяет отправить сериализуемую команду внутрь другого window, и внутри этого window подписаться на объект message, прочитать то, что было в команде. И отреагировать на нее.

updateDoggy() {    this.iframe.contentWindow        .postMessage({ command: 'updateDoggy' });}

Давайте реализуем updateDoggy через postMessage. В родительском документе у нас будет отправляться сообщение с командой updateDoggy внутрь iframe.

window.addEventListener('message', (e) => {    if (e.data.command === 'updateDoggy') {        widget.updateDoggy();    }})

И внутри iframe нам нужно будет написать вот такой код, который подписывается на события message, а если там updateDoggy, то дергает updateDoggy у виджета, который перерисует нам картинку.


Ссылка со слайдов

Посмотрим, что нам дает использование iframe. В первую очередь все взаимодействие с виджетом, который рисуется внутри iframe, становится асинхронным. postMessage асинхронный API. До этого мы могли синхронно вызывать методы, а сейчас мы этого делать не можем.

События, которые происходят внутри iframe, наружу не всплывают. Если вы хотите реагировать, например, снаружи на то, что пользователь кликнул внутри виджета, то вам нужно отправлять postMessage наверх. Использовать addEventListener напрямую у вас не получится событие через iframe не всплывет.

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

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

Что мы в итоге получаем? У нас сильно усложняется код. И еще появляются накладные расходы.

Если мы вспомним, как рисовался наш виджет, вставляемый через скрипт, это это выглядело бы так. У нас бы загружалась страничка, загружался CSS, JS. Дальше, когда виджет рисовался бы, каждый виджет запрашивал бы для себя картинку.

Если мы рассмотрим наш новый вариант с iframes, мы увидим такое. Внутри каждого виджета загрузится документ, у нас загрузится CSS, который там нужен, и JS, который внутри этого документа исполняется.

Для первого виджета, для второго. Сколько у вас их будет на странице, столько будет загрузок этих файлов?

Ссылка со слайда

Здесь могло бы помочь кеширование, но недавно браузеры сделали так, чтобы изолировать кеши друг от друга между различными сайтами. Это нужно, чтобы предотвратить трекинг посещения пользователем одного сайта с другого. То есть если на сайте номер 1 используется какая-то библиотечка, сайт номер 2 тоже может ее подключить и посмотреть через Performance API, была они ла загружена из кеша. Если да, то пользователь, скорее всего, до этого посещал сайт 1 и это можно как-то использовать. Браузеры сейчас от такого поведения стараются пользователей защищать.

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

К чему это приводит, если мы пытаемся строить микрофронтенды на виджетах, которые загружаются каждый в независимом iframe?

https://website.ru/    https://yastatic.net/react/16.8.4/react-with-dom.min.js    Widget #1        <iframe> https://widget-1.ru/            https://yastatic.net/react/16.8.4/react-with-dom.min.js    Widget #2        <iframe> https://widget-2.ru/            https://yastatic.net/react/16.8.4/react-with-dom.min.js

Допустим, у нас есть наш основной сайт, на котором подключен React. Есть виджет номер 1, на котором подключен React допустим, даже тот же самый bundle. И виджет номер 2 с еще одного хоста, на нем тоже подключен React.

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

Итак, что мы получаем с iframe? У нас есть полная изоляция виджетов в CSS. Есть полная изоляция JS, потому что документы не зависят друг от друга. Есть независимые мониторинги, потому что внутри каждого iframe свой собственный window, на котором мы можем ловить ошибки.

Но при этом сильно усложнился код, поскольку появилась асинхронность.

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

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

Выглядит так, будто у нас есть два варианта: один с использованием скрипта, один с использованием iframe.

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

Здесь поможет так называемый friendly <iframe>. Вы еще можете встретить название same-origin <iframe>, или anonymous <iframe>.

const globalOne = window;let iframe = document.createElement('iframe');document.body.appendChild(iframe);const globalTwo = iframe.contentWindow;

В чем идея? Есть глобальная область наш текущий window. Можно создать через createElement новый iframe и зааппендить его на страничку. При этом заметьте, что я внутри этого фрейма никакой документ не загружаю, дополнительного запроса за HTML здесь не будет и внутри документа окажется пустая страничка, которую туда автоматически подложит браузер.

Теперь contentWindow этого iframe можно рассматривать как еще один независимый контекст, который мы можем использовать.

foobar.js:
window.someMethod = () => {...}

Давайте подумаем, зачем. Мы можем в этом контексте исполнять скрипты.

Вот наш скрипт foobar.js, который в глобальную область добавляет метод. Как подключить его внутрь нашего нового контекста? Создаем скрипт, ставим ему src и аппендим внутрь head нашего iframe.

const script = document.createElement(script);script.src = 'foobar.js';globalTwo.head.appendChild(script);

Теперь, чтобы взаимодействовать с кодом внутри этого скрипта, нам больше не нужно использовать postMessage, потому что контекст у нас same-origin:

globalTwo.postMessage();

globalTwo.someMethod();

Можно просто напрямую вызвать сам метод, и это будет работать, браузер не будет это блокировать.

Давайте попробуем, используя эту идею, переписать наш виджет еще раз.

Единственное, нам надо понять, где у нас будет находиться верстка. Если помните, я сказал, что внутрь friendly frame документ мы не загружаем, но верстку надо где-то отрисовать.

А верстку мы будем рисовать в контексте родительской страницы и будем использовать Shadow DOM. Попробуем взять лучшее из двух подходов, которые мы до это рассматривали.

Как теперь будет выглядеть фабрика нашего виджета?

const iframe = document.createElement('iframe');document.head.appendChild(iframe);const script = document.createElement('script');script.src = 'doggy-widget-inner.js';const loaded = new Promise((resolve) => {    script.onload = resolve;});loaded.then(() => {    iframe.contentWindow.init(config);})iframe.contentDocument.head.appendChild(script);

Создаем в нем iframe, загружаем внутрь этого iframe скрипт и сохраняем promise, который зарезолвится, когда этот скрипт загрузится.

После того, как он прогрузился, мы вызовем внутри нашего виджета init и передадим его config, который отрисует виджет внутри. Нам осталось зааппендить скрипт в head нашего iframe.

Как теперь преобразуется doggy-widget-inner.js, код, который работает внутри фрейма?

window.init = (config) => {    const widget = new Widget(config);    window.widget = widget;};

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

Как в итоге все будет работать? Если мы отрисуем таким способом два виджета на страничке, то получим примерно такое DOM-дерево.



Ссылка со слайдов

Для каждого виджета у нас будет в хэде скрытый friendly iframe, который пользователь не видит, но при этом код внутри него исполняется и с ним можно работать. Для каждого виджета в контейнере, который мы передали, будет использоваться shadow root, внутри которого будет находиться верстка этого конкретного виджета. Вот для первого виджета, а вот для второго.

Код целиком:

<head>    <iframe>        #document            <html>                <head>                    <script src="doggy-widget-inner.js"></script>                </head>                <body></body>            </html>    </iframe>    <iframe>        #document            <html>                <head>                    <script src="doggy-widget-inner.js"></script>                </head>                <body></body>            </html>    </iframe></head><body>    <div id="widget-1">        #shadow-root            <link rel="stylesheet" href="doggy-widget.css">            <div class="doggy-widget">                <img class="doggy-widget__img"/>                <button class="doggy-widget__btn"/>            </div>    </div>    <div id="widget-2">        #shadow-root            <link rel="stylesheet" href="doggy-widget.css">            <div class="doggy-widget">                <img class="doggy-widget__img"/>                <button class="doggy-widget__btn"/>            </div>    </div>    <script src="doggy-widget.js"></script></body>

Что этот подход нам дает? Мы получаем:

  • Полную изоляцию наших виджетов в CSS, потому что используем Shadow DOM.
  • Полную изоляцию в JS, потому что код работает внутри выделенного iframe, и какой-либо monkey-patching в родительском документе на него никак не влияет.
  • Независимые мониторинги, потому что код виджета работает, опять-таки, в независимом window, где мы можем слушать эксепшены.
  • Работающее кеширование, так как контекст same-origin в браузере больше не изолирует кеши между виджетами.

При этом все еще есть:

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

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

Немного поговорим о том, что ждет нас в светлом будущем. Там нас ждет спецификация Realms API. Она сейчас находится в TC39 на Stage 2, это draft. Активно идет написание стандарта. Спецификация развивается. Надеемся, что скоро она перейдет на stage 3.

Что она позволяет делать? Вспомним, как мы создавали friendly frame. У нас был глобальный контекст globalOne. Мы создавали элемент iframe, аппендили его в документ и получали globalTwo еще один независимый контекст внутри этого фрейма.

const globalOne = window;let iframe = document.createElement('iframe');document.body.appendChild(iframe);const globalTwo = iframe.contentWindow;

const globalOne = window;const globalTwo = new Realm().globalThis;

Realms позволяет это заменить на такую конструкцию. Появляется новый глобальный объект Realm. Создав инстанс Realm, вы получаете внутри него globalThis, который является как раз тем самым независимым контекстом, который при этом работает оптимальнее, чем отдельный iframe.

Как внутри Realm можно будет исполнить код? Через вызов импорта.

const realm = new Realm();const { doSomething } = await realm.import(    ./file.js');doSomething();

Заимпортируем какой-нибудь JS-файл, который экспортирует метод doSomething. Его сразу можно будет вызвать, он будет работать в контексте Realm независимо от основной странички.

У этого API даже есть полифильчик, который построен как раз с использованием friendly frame. Правда, полифил, похоже, стал deprecated. Там года два уже не было коммитов, и он сильно отстал от текущего драфта спеки. Но надеюсь, с развитием спецификации его оживят.

Итоги


Используйте микрофронтендный подход с умом, только если вам это действительно нужно. Выбирайте подходящую вам техническую реализацию. И следите за спецификациями. Эта тематика активно развивается, в будущем у нас появятся более удобные способы строить микрофронтенды. Спасибо!
Подробнее..

Единый UI-кит и синхронизация дизайна в Учи.ру. Часть 1

20.02.2021 10:19:11 | Автор: admin

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

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

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

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

И для разработчика, и для дизайнера

Создавая UI-кит, мы постарались сделать так, чтобы дизайнер мог участвовать в развитии интерфейса, не привлекая разработчиков. Он выбирает размер, цвет, шрифт, поведение компонентов прямо из Figma для этого там есть отдельная доска, на которой задаются дизайн-токены. Например, дизайнер может обозначить основной цвет (color-primary) как фиолетовый, тогда для визуальных компонентов будет использоваться именно он.

Разработчики применяют UI-кит при создании сервисов. Теперь не нужно писать компоненты заново достаточно обратиться к общей библиотеке.

Выбираем основу библиотеки

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

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

Также мы хотели оставить себе пространство для маневра, чтобы не быть привязанными к определенному фреймворку. Отчасти потому, что несколько решений уже развивались не на рекомендуемом в компании стеке (React). Но в большей степени из-за нежелания безусловно завязываться на одной технологии. Учитывая скорость развития отрасли, мы должны были обеспечить командам возможность экспериментировать с технологиями без отказа от базы готовых UI-элементов.

Библиотек и фреймворков для создания веб-компонентов много. Например, ресурс WebComponents.dev, кроме предоставления исчерпывающего списка вариантов, обновляет их и информацию об их характеристиках. Мы составили свой топ-3: связку lit-element + lit-html и фреймворки Stencil, Hybrids выделили наиболее значимые критерии и сравнили по ним. На момент выбора это было в начале июня 2020 года получили такую картину:

Критерии

Фреймворк/библиотека

lit-element + lit-html

Stencil

Hybrids

JavaScript ES3+

+

+ (при использовании полифиллов)

+

JavaScript ES6+

+

+

-

TypeScript

+

+

+

JSX

+

+

+

Выгрузка для React

-

+ (при использовании плагина)

-

Выгрузка для Vue

-

+ (при использовании плагина)

-

Поддержка работы без фреймворка

+

+

+

Поддержка IE11

+

+ (при использовании полифиллов)

-

Поддержка современных браузеров

+

+

+

Поддержка плагинов / возможности расширения

-

+

-

CSR

+

+

+

SSR

+ (при использовании доп. библиотеки)

+

-

Подключение ассетов и CSS как отдельных файлов

-

+

-

Хорошая документация

+

+

+

Развитое комьюнити

+

+

+

Что за выгрузка в React/Vue?

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

На первый взгляд, lit-element + lit-html и Stencil показались почти равноценными. Первые не поддерживали плагины или не давали возможности расширения, соответственно не решали наш вопрос с выгрузкой, не поддерживали подключения ассетов и CSS как отдельных файлов, а со вторым на помощь пришли плагины. Для большей ясности мы ввели коэффициенты для каждого критерия и остановились на Stencil.

Если у вас похожий стек, можете посмотреть нашу таблицу.

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

Когда мы выбирали инструменты, оценивали, насколько изменится размер бандла сайта и на React, и на Vue. Сначала все было не очень хорошо, потому что демосайт на React весил без библиотеки 2,5 Мбайт, а с библиотекой 5 Мбайт. Бандл оказался таким большим потому, что по умолчанию Stencil предоставляет библиотеку с полифилами с поддержкой старых браузеров. Чтобы уменьшить размер бандла, мы использовали решение для выгрузки компонентов в виде отдельных файлов, с которыми очень хорошо работают фреймворки. Также мы отдельно вынесли шрифты и подключаем их по URL так мы добились, чтобы с библиотекой на Stencil сайт весил 3 Мбайт. Это хорошо, хотя уже сейчас понятно, что можно еще поработать над размером дополнительных компонентов.

От Figma до готового компонента

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

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

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

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

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

Для презентации UI-кита мы используем Storybook. Бандлы выкладываются сначала на внутренний ресурс. Дизайнер или менеджер может зайти, пощупать какой-то компонент, изучить особенности работы, почитать описания настроек. Например, можно сделать кнопку активной или неактивной и посмотреть, как это выглядит, еще до публикации бандла. Во второй вкладке таблицы вы найдете сравнение интерфейсов для UI-кита.

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


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

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru