Вы находитесь на странице: 1из 46

Идеальный

виджет
Опыт travelpayouts
Виджеты
Виджеты
• Проблемы виджетов;
• Тонкости разработки;
• Пуленепробиваемый код.
Travelpayouts
• 5 лет на рынке (до этого были в составе Aviasales);
• Более 100 000 аффилиатов;
• Более 600 млн ₽ выплат;
• 18 634 работающие конфигурации виджета
поисковой формы;
• Ещё 8 виджетов и вайтлейблы.
Виджеты
• Легковесные;
• Работающие.
Отличие от других проектов
• Размер;
• Агрессивная среда размещения;
• Локализации + кастомизируемость;
• Время на разработку (но это не точно).
Любой разработчик сможет
за пару дней
сделать виджет на Реакте.
Очень простой виджет
Какие были проблемы
• 200кб дистрибутив;
• Неизолированные стили;
• Непродуманный код для вставки.
Что такое 200кб
для виджета?
Средний размер по данным HTTPArchive http://bit.ly/2hmIF3r:
• 3300кб страница;
• 450кб JS gzipped (25 js-файлов);
• 10мбит средняя скорость интернета в России;
• 6250кб за 5 секунд.
Introducing Mewtwo
Чего мы смогли добиться
• 45кб js + 10кб CSS + 7кб Logo = 55кб + 7кб;
• Эффективность, вымученная а/б тестами;
• Почти не было жалоб от партнёров после деплоя
на 100%.
Как уместить виджет в 50kb
• NPM as a framework:
- Babel-plugin-lodash / submodules / lodash-es;
- date-fns / js-joda вместо moment.js ?.
• Monkberry.js for templates;
• Постоянный контроль итогового размера дистрибутива:
- Size Limit;
- Webpack bundle analyzer;
- jsize.
Попытка загрузить виджет
быстрее основного контента
• Не забывать про async;
• Разделение загрузчика и контента;
• Монолитный виджет с закешированным конфигом.
Конфликты CSS и JS
Проблемы с CSS
• Коллизия имён классов;
• Глобальное переопределение свойств;
• Более сильные селекторы.
Изолирование стилей
• All initial
01. #mydiv {
02. all: initial; /* blocking
03. inheritance for all properties */
04. }
05. #mydiv * {
06. all: unset; /* allowing inheritance
07. within #mydiv */
08. }
09. #mydiv::before,
10. #mydiv::after,
11. #mydiv *::before,
12. #mydiv *::after { Не работает в IE и Opera Mini
13. all: unset;
14. }
Изолирование стилей
• All initial (не работает в IE и Opera Mini);
• Iframe (влияет на скорость загрузки).
Изолирование стилей
• All initial (не работает в IE и Opera Mini);
• Iframe (влияет на скорость загрузки);
• Shadow DOM (работает в Chrome, Opera и Android).
Изолирование стилей
• All initial (не работает в IE и Opera Mini);
• Iframe (влияет на скорость загрузки);
• Shadow DOM (работает в Chrome, Opera и Android);
• CSS Modules.
Изолирование стилей
• All initial (не работает в IE и Opera Mini);
• Iframe (влияет на скорость загрузки);
• Shadow DOM (работает в Chrome, Opera и Android);
• CSS Modules;
• CSS-in-JS styled CSS.
Изолирование стилей
• All initial (не работает в IE и Opera Mini);
• Iframe (влияет на скорость загрузки);
• Shadow DOM (работает в Chrome, Opera и Android);
• CSS Modules;
• CSS-in-JS styled CSS;
• Наш собственный вариант.
Шаг 1
Закрываем стандартные свойства от внешнего мира.

Внутри главного враппера виджета нужно


нормализовать стили для всех используемых тегов.
CSS Normalize, завёрнутый внутрь враппера, плюс
секретный кот:
01. div, span, object, nav, h1, h2, h3, p, a, em, img, strong, ul, li, fieldset, form, label,
02. legend, nav, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas,
03. footer, header, hgroup, section, input, textarea, select, *::before, *::after, & {
04. float: none;
05. box-sizing: border-box;
06. margin: 0;
07. padding: 0;
08. border: 0;
09. background: none;
10. background-color: transparent;
11. box-shadow: none;
12. vertical-align: baseline;
13. text-align: left;
14. text-indent: 0;
15. text-transform: none;
16. text-shadow: none;
17. white-space: normal;
18. letter-spacing: 0;
19. font: inherit;
20. font-style: normal;
21. font-size: 100%;
22. line-height: 1;
23. position: initial;
24 }
Шаг 2
Делаем наши свойства сильнейшими.
Для того, чтобы получить самые сильные селекторы,
используем при сборке в прод PostCSS-importantly.
Шаг 3
Избавляемся от коллизий.
Для получения уникальных селекторов используем
при сборке в прод gulp-class-prefix.
Ducklett Blissey

Mewtwo
Chansey Weedle
Что мы сделали
• Wrapper CSS reset; 01.

02.
.mewtwo-widget .mewtwo-flights-origin {

position: relative!important;

• PostCSS Importantly; 03. min-width: initial!important;

04. max-width: initial!important;

• gulp-class-prefix. 05. display: inline-block!important;

06. margin-right: 1%!important;

07. width: 19%!important;

08. vertical-align: top!important;

09. }
SVG и логотипы
• Кастомизируемые цвета в SVG:
- Определять их в monk-шаблоне;
- CSSX в js.
• SVG с логотипами в отдельном файле 7kb.
Код для вставки
Любое усложнение кода приведёт к дополнительным
тикетам в поддержку.
Как можно вставить виджет
• script + div#id (div.class, div[role], etc).
01. <div id="widget"></div>

02. <script src="//travelpayouts.com/widget" async></script>


Как можно вставить виджет
• script + div#id (div.class, div[role], etc);
01. <div id="widget"></div>

02. <script src="//travelpayouts.com/widget" async></script>

• script.
Как передать параметры
Data-attributes
01. <script src="//www.travelpayouts.com/widget" data-width="100%"

02. data-border_radius="2" data-show_logo="true" data-

03. show_hotels="true" async></script>


Как передать параметры
script?param1=1&param2=2
01. <script src="//www.travelpayouts.com/widget?

02. width=100%&border_radius=2&show_logo=true&show_hotels=true"

03. async></script>
Как передать параметры
Inline js params
01. <script>

02. const WidgetParams = {

03. width: '100%',

04. border_radius: 2,

05. show_logo: true,

06. show_hotels:true

07. }

08. </script>

09. <script src="//www.travelpayouts.com/widget" async></script>


Как передать параметры
Кэшировать выбранные параметры прямо в код
виджета по хэшу с возможностью их
переопределения инлайновым js
Как передать параметры
01. <script charset="utf-8" type="text/javascript">

02. window.TP_FORM_SETTINGS = window.TP_FORM_SETTINGS || {};

03. window.TP_FORM_SETTINGS["1d8b372abc912411e4f5d247d117990d"] = {

04. "border_radius": "2",

05. "width": 550,

06. "show_logo": true,

07. "show_hotels": true

08. };

09. </script>

10. <script charset="utf-8" src="//www.travelpayouts.com/widgets/

11. 1d8b372abc912411e4f5d247d117990d.js?v=1062" async></script>


Айфреймы
• Все попапы должны уместиться внутри айфрейма;
• Подстраивать высоту айфрейма под высоту
контента;
• Настроить передачу событий между айфреймом

и документом.
Настройка виджета
• Генерация кода для вставки;
• Сохранение настроек виджета
и сброс кэша;
• Обновление демо-виджета

на лету.
Виджеты
• Следите за размером дистрибутива;
• Изолируйте CSS;
• Предотвращайте возможность конфликта версий

js-библиотек;
• Разрабатывайте виджеты, моментально готовые к работе
после загрузки;
• Помните про iframe и локализации;
• Делайте максимально простой код для вставки.
Дополнительно
по теме
Third-Party JavaScript
Ben Vinegar and Anton Kovalyov
Спасибо
за внимание!
Игорь Вечканов
Front-end developer, travelpayouts
igor.vechkanov@aviasales.ru

Вам также может понравиться