Pull to refresh
310.57
Конференции Олега Бунина (Онтико)
Конференции Олега Бунина

Как стать свободным от «цепей» старых браузеров

Reading time 9 min
Views 5K
Люди не готовы отказываться от старых друзей, старых традиций и старых-добрых предпочтений. А еще некоторые из них привыкли к устаревшим версиям браузеров, а современное ПО устанавливать отказываются. О том, что делать, если вы стали заложником старых браузеров, рассказал в своем докладе на конференции «Frontend Conf» руководитель направления разработки ДомКлик Денис Красновский.



Знакомьтесь: это Slowking, Slowpoke, Slowbro и Slow web.



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

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

Кто-то скажет: «ОК, вижу белый экран: сейчас загрузится! Все бывает. Игры тоже долго грузятся, но люди ведь от этого не перестают в них играть». Но для бизнеса важно, чтобы ваш проект хорошо индексировался. Google отдает предпочтение оптимизированным сайтам: тем, кто постарался сделать mobile-friendly приложение, и у кого оно быстро грузится.

SEO


Хочу условиться о том, что под приложением в этой статье всегда имеется в виду Web, то есть неважно – это просто лэндинг или Rich JavaScript Application.

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

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

SEO – это первый шаг, второй – впечатления пользователей.

User experience





Даже если вы находитесь на хорошем месте в выдаче поисковика — это еще не все. Нужно поработать над user experience. Именно в этот момент белый экран, особенно если он грузится довольно долго, начинает напрягать. Долгая загрузка связана, скорее всего, с большим количеством статики. Под статикой подразумеваются js, css, svg, png — в общем, все, что мы собираем для нашего приложения.

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

Существует метрика Retention, в которой можно увидеть количество пользователей, которое вы смогли удержать после того, как они воспользовались вашим приложением. Например, я посмотрел первую серию «Игры престолов», и у меня негативный опыт: все грузится слишком долго, постоянно появляются какие-то проблемы. Скорее всего, я уйду к конкурентам. Возможно, именно они предоставят мне то, что я не получил с первым результатом в выдаче.

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



Все мы привыкли пользоваться stylelint, ESLint, которые проверяют наши js и css. Но почему бы нам не взять за основу Lighthouse?

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

Я хочу рассказать о том, как стать свободным от «цепей» старых браузеров. Давайте рассмотрим историю о взлетах и падениях. Все персонажи вымышлены, все совпадения — случайны.

This is how we do


Как-то раз ко мне обратились с предложением: «Давайте вы сделаете офигенное приложение: быстро, качественно, а еще у него должен быть хороший перфоманс». Нужно было делать Single Page Application, что подразумевало борьбу за прорисовку.

Для себя мы определили паттерны, по которым работать:

  • Не оверхедить. Оверхед – это когда люди вместо того, чтобы написать простой кусочек кода, начинают изобретать ракету. Зачем? Если задать этот вопрос напрямую, услышите что-то подобное: «В будущем нам, возможно, это понадобится!». Этого будущего для уже написанного куска кода может и не быть. Не исключена и вероятность того, что через день его удалят из кодовой базы. Мы оставляли только то, что нужно здесь и сейчас, и что несет реальный профит для проекта. Меньше кода – меньше багов, а еще это значит, что будет меньше вес бандла и лучше перфоманс.

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

  • Не использовать общие компоненты, не закрепленные за командой. Возможно, эта тема больная для многих из вас. На моей памяти не было ни одного сета общих компонентов, которым были бы довольны все.

  • Оптимизировать ресурсы. Следующий логичный шаг – оптимизировать ресурсы: js, css, html, картинки и прочее. Мы делаем это с помощью Webpack, OptimizeCSS Plugin, UglifyJS, Tercer, HTMLWebpack Plugin.

  • Настроить code splitting. Например, code splitting в Webpack можно получить с помощью dynamic import в две строчки.

  • Оптимизировать доставку ресурсов. После dynamic imports логичным является либо prefetch, либо preload данных, которые объявляются ровно в том же месте, где dynamic imports, с помощью магических комментариев для Webpack. Там же вы можете указать приоритет ресурса: как быстро нужно его начинать скачивать. После того, как у нас все скачалось, с помощью prefetch мы можем подтянуть остальное. Пользователь этого не заметит. Но после того, как он нажмет кнопку «Залогиниться», его перебросит на другую страницу, и все его ресурсы останутся в кэше. То же самое можно провернуть с данными. Но основной месседж в том, что интерфейс не доставляет пользователю никаких неудобств.

  • Кэшировать и сжимать статику (например использовать gzip).

Вес css + js, без gzip


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



Этот момент показателен. Если мы заходим на страницу с 8 КБ, зачем тащить туда все остальное? Дайте эти 8 КБ пользователю, и пусть у него все рисуется.

Диагностика


Мы сделали приложение, оно работает. Как проверить перфоманс?

  • Lighthouse. Им можно воспользоваться в Chrome DevTools и в Tabaudit. Также вы можете подключить CLI, и поработать с ней.

  • PageSpeed Insights. Там можно увидеть немного другой интерфейс, чем в Lighthouse.

  • Внутренние ощущения (я серьезно!).

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

Браузеры кричат, как в фильме: «Somebody, please, get this browser a polyfill!».

Нас просили поддержать не только IE, но и Chrome v35 и Safari v10. Казалось бы, в чем проблема? Поддержали, добавили пару строчек кода — и все хорошо! Но дело в том, что мы уже дали пользователю почувствовать, что приложение летает. Это как будто вы посадили в ресторане клиента за столик у окошка на 86 этаже, и у него дух захватило от открывшегося перед ним вида. А через пять минут подошли к нему и предложили пересесть к туалету. Мы не хотели допустить такого эффекта, поэтому начали искать варианты работы со старыми браузерами.

Варианты работы со старыми браузерами


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

  • Повесить заглушку для старых браузеров. Это довольно аристократичное решение, и оно мне нравится. Вешаем для старых браузеров заглушку и говорим: «Друг, скачай себе новый браузер». Но и этот вариант не подходит, поскольку есть огромное количество людей, которые пытаются зайти, скажем, с Windows XP.

  • Заполифилиться. Этот вариант плох из-за того, что мы выбираем простой путь, а web никогда не будет быстрым.

  • Сделать сплит между новыми и старыми браузерами. Его мы и решили попробовать.

Рецепт


На самом деле идея проста. Для ее воплощения, нам нужны:
  • package.json. Это своего рода интерфейс для работы человека с приложением, или — в случае, если речь идет о пакете — приложения с приложением.
  • home made script. Немного скриптов.
  • webpack. Модуль бандлер, который поможет собрать наш js, css, svg.
  • babel. Он транспайлит код нового стандарта в тот код, который понимают более старые браузеры.
  • browserslist. Необходим для того, чтобы указать, для каких браузеров мы что-то собираем.
  • nginx. Это последний шаг — вишенка на торте хайпа. Еще полтора года назад я сам считал, что это не мое. Но — к счастью, или к сожалению — жизнь все-таки привела меня к nginx. Он будет нам нужен для того, чтобы финально решать, какие файлы и какому пользователю нужно отдать.


package.json


Во всем package.json нас сейчас интересуют три строчки:



Первые две строки — инструкция к сборке. Ключевой особенностью является указатель переменной окружения TARGET=old и TARGET=modern. Эту переменную мы будем использовать далее.

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

Еще один важный нюанс, о котором иногда забывают: && — это последовательное выполнение, а & — параллельное выполнение. Нам не нужно ждать, пока у нас билдится modern билд, мы запускаем их параллельно.

target.js


Нам нужно написать совсем немного скриптов.



Что здесь происходит? Мы преследуем единственную цель: собрать статику с хорошими браузерами в отдельную папку, а все остальные, кроме «мертвых» (больше 1%) — в другую папку. Это своего рода сервис. Мы объявляем полифилы, которые нам понадобятся. Переменную окружения используем для того, чтобы вернуть отсюда именно тот конфиг, который нужен Webpack и Babel.

webpack.prod.js


Все, что нам нужно сделать в Webpack, это прокинуть полифилы:



Потом перейдем в Babel.config.js:



Babel преобразует наш офигенный код в более старый, который не нравится нам, но нравится браузерам. При работе с Babel и при поддержке старых браузеров, нам необходим babel-polyfill.

Это мощная машина, которая много весит. В этот момент мы тоже указываем таргеты.

Babel-polyfill используется с параметром useBuiltIns с флагами:

  • 'entry' => 384 KB;

Этот подход рекомендуют все гайды. Но нужно учесть, что вы обязаны заимпортить его в индексовый файл, или объявить в entry Webpack.

Итого, из исходных 294 КБ они превращаются в 384 КБ кода.

Я выбираю другой вариант.

  • 'usage' => 334 KB.

При таком подходе ваш вендор ужимается до 334 КБ, и вы не ставите babel-polyfill в зависимости. Файлики, в которых что-то используется, вырастут примерно на килобайт.

Путем нехитрых манипуляций мы получили две сборки:



Я упоминаю Internet Explorer, поскольку для меня он является олицетворением старых браузеров.
Это разница:

  • css ~ 1 KB – наверное, мы не такие изощренные верстальщики;
  • js ~ 69 KB – годная тема.

Во фронтенде — по крайней мере у нас — принято биться за каждый килобайт.

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

У меня лапки


Иногда в браузере можно увидеть 'last 2 versions'. Это означает, что вы решили поддерживать две версии всех браузеров, даже мертвых.

Добавьте useBuiltIns: 'entry', и разница между хорошим билдом и том, о котором мы сейчас говорим, будет составлять:

  • css ~ 25 KB (в префиксе для мертвых браузеров);
  • js ~ 117 KB.

И не нужно забывать о том, что эти цифры для разных случаев будут разными.

nginx split


Вишенка на торте хайпа, о которой я говорил.



Мы находимся в nginx и будем использовать директиву map, локальную переменную http_user_agent. Кроме того, объявили переменную template. В нее запишем название индексового файла, который будем отдавать пользователю.

Важный момент: мы получаем user_agent на regex. И если user_agent с версией Chrome от 0 до 74, то мы отдаем old индекс. Для всех остальных современных браузеров отдаем modern-индекс.
listen 5050 означает то, что при запуске nginx, вы зайдете на local host 5050, и он начнет следовать инструкциям, которые вы написали, и раздавать то, что вы хотите. В данном случае (строчка root) мы говорим, что по такому-то пути на компьютере рнаходится папка dist (это папка в проекте), и туда нужно отдатьпеременную template. Это либо old индекс, либо modern индекс.

Теперь смотрим, что произошло:

Chrome v74




Про v74 мы условно сказали, что это старый Chrome. Здесь есть строчка, которая заматчилась — значит, все работает.

Chrome Canary v76




Работает надежно, как швейцарские часы. Но фронтенд в целом надежен как швейцарские часы (в отличие от бэкенда).

Как выглядит реальный файл?

Real world nginx map


Он выглядит следующим образом:



В данном случае мы уже объявили переменную. Для чего мы это сделали и почему не объявили ее выше, что казалось бы логичным ходом? В nginx нельзя объявить переменную выше, чем скоуп сервер. Интересно, что нельзя сделать директиву map на скоуп сервер. Поэтому код выглядит немного странновато, но он работает.

Для чего мы написали здесь столько переменных? Если вы какой-то причине решите переименовать файлик и допустите ошибку, nginx не будет на это ругаться. Однако если здесь будет не переменная, пользователям в разбросе Chrome 0-9 будет отдаваться не то, что они хотят. И вы, как человек, у которого есть самая последняя топовая машина и самый последний топовый браузер, никогда об этом не узнаете. Насколько быстро всплывет эта ошибка, неизвестно. Почему это происходит большинство разработчиков так и не поймут. Поэтому в данном случае лучше делать все через переменные.

Наверное, вы знаете, что есть сервисы Polyfill.io, и существует вариант проверять на клиенте, работает ли тот или иной метод, и, в зависимости от полученных данных, собирать статику. Скажу сразу: этот вариант рассматривать не стоит. Почему?

Вы объявляете Polyfill.io render-blocking скриптом, потому что не можете загружать свои скрипты дальше, ведь иначе JavaScript не станет работать. Поэтому мы сначала скачиваем html, видим Polyfill.io, идем в него, и он уже решает, что нам нужно. При таком подходе о перформансе можно забыть.

По той же причине не работает проверка, есть ли метод. Вы просто создаете дополнительные round-trip’ы, которые замедляют прорисовку.

Лучше всего пойти легким путем, о котором я рассказал. У человека, который знает Webpack и Babel, создать сплит между старым и новым браузером получится за два-три часа. А если он с ними не знаком и времени потребуется больше, это все равно стоит того.

Как говорил Альтрон:

«Я покажу вам нечто прекрасное ( у нас это web, тонущий в мегабайтах JavaScript).
Вы хотите перформанс, но не готовы к эволюции, а я свободен ото всех цепей».

Такой подход вас избавляет от всех цепей и позволяет не пересаживать человека к туалету, если он уже почувствовал вкус великолепного вида с 86 этажа.
Tags:
Hubs:
+13
Comments 2
Comments Comments 2

Articles

Information

Website
www.ontico.ru
Registered
Founded
Employees
11–30 employees
Location
Россия