Привет! Сегодня поговорим про оптимизации, что влияет на метрики, расскажу про best practices и случаи из жизни :)
Выделю три основные направления возможных оптимизаций:
- размеры бандлов и их доставка
- загрузка и отрисовка страницы
- взаимодейстивие со страницей, отзывчивость, UX
1. Про бандлы и доставку:
Кажется очевидным, но почему-то часто об этом забывают:
- включите сжатие gzip/brotli для ресурсов
- используйте в вебпаке хеш от контента в имени файла, и включите кеширование на подольше (у нас на месяц)
Тоже очевидно, но всё же, убедитесь, что вебпак собирает бандлы в продакшен-режиме с включенной опцией minimize:
Следующим шагом можно настроить в вебпаке разбивку на чанки. Чтобы это сделать, неплохо для начала проанализировать, из чего состоит итоговый бандл. Например, с помощью webpack-bundle-analyzer npmjs.com/package/webpac…
Распространён подход, когда в один чанк (или несколько) выносят зависимости node_modules, а в другой код приложения. Это кажется не очень оптимальным, поскольку при таком подходе при первой загрузке приложения пользователь всё равно скачает всё.
Лучше, изучив состав бандла через webpack-bundle-analyzer, выделить в отдельный чанк общие зависимости для всех роутов приложения (например, реакт, роутер, redux, и UI-kit), а зависимости, используемые в 1-2 страницах, включить в состав чанка этой страницы
Для генерации отдельного чанка для каждого роута отлично подходит React.lazy() в сочетании с react-router ru.reactjs.org/docs/code-spli…
Дать файлам чанков человеко-читаемые имена поможет волшебный комментарий для вебпака:
Хорошим способом сократить объем кода, скачиваемого при первой загрузке React приложения, будет импортировать с lazy() все компоненты, с которыми пользователь не взаимодействует сразу: модалки, скрытые компоненты, и подобное.
Некоторые npm пакеты могут существенно увеличить объем бандла кодом, который никогда не будет использован. Например, moment.js по-умолчанию включает все возможные локали, а lodash — все хелперы.
Блокируют отрисовку страницы:
- Стили, подключенные без атрибута media,
- стили, подключенные с атрибутом media, который совпадает с текущими параметрами устройства,
- скрипты без атрибута async/defer.
Стили и скрипты будут загружены, даже если они не блокируют отрисовку.
Чтобы немного упростить браузеру задачу отрисовки:
- разделите CSS на файлы так, чтобы один файл — один media query (плагин: npmjs.com/package/postcs…),
- подключайте скрипты с async/defer, и проверяйте в них событие DOMContentLoaded
Пользователь, заходя на страницу, видит только какую-то её часть. Важно сделать так, чтобы эта видимая часть отобразилась как можно быстрее. Для этого можно выделить стили, необходимые для отрисовки первого экрана, и заинлайнить их. Плагин для вебпака: github.com/GoogleChromeLa…
Применение critical css позитивно скажется на метриках, например, Largest contentful paint
На контентные метрики (Largest contentful paint / First meaningful paint) влияет и то, как подключаются и используются шрифты.
Мы однажды обнаружили, что на одном из сервисов загружался, но не использовался, кастомный шрифт. После его удаления, метрика FMP улучшилась на 76%!
Ещё немного про шрифты:
- формата woff2 достаточно в большинстве случаев (caniuse.com/?search=woff2);
- подключайте шрифт с preload;
- используйте font-display: swap;
Про изображения:
- указывайте width/height, так браузер заранее зарезервирует место для картинок
- для контентных картинок — атрибут loading="lazy" (caniuse.com/loading-lazy-a…) для нативной загрузки по скроллу (полифил: github.com/mfranzke/loadi…)
Совет от кэпа: убедитесь, что картинки минимизованы и имеют адекватные размеры! Особенно, если картинки могут загружать пользователи. В одном нашем сервисе мы сэкономили 10мб просто на том, что привели изображения к ширине 1024px и качеству 85% ¯\_(ツ)_/¯
Кулстори про клиентский и серверный рендеринг. Есть мнение, что рендерить страницу на сервере быстрее, чем на клиенте. Поэтому мы выпилили реакт на одной из статичных страниц, и переписали её на чистом html, который собирается через Django на бэке (Django там уже был) ->
Постепенно к странице появлялись всё новые требования: сначала кастомизации в зависимости от тарифного плана и страны пользователя, а через год — от нескольких десятков параметров. Настройки делали на бэке условиями в темплейте, в итоге time to first byte составил 2 сек
Поддерживать это стало очень сложно, решили снова переписать на реакте. Страница стала отдаваться за 200мс, но выросли TTI и CLS (август-сентябрь на графике):
Тогда придумали к̶о̶с̶т̶ы̶л̶ь изящное решение: для видимой части сверстали скелетон (штуку как на картинке) и заинлайнили его стили в <style>. Поместили этот код внутри тега, куда рендерится реакт, чтобы он заменялся на реактом на готовую страницу с контентом.
Если нужно передать через шаблон данные с сервера на клиент (например, initial state для redux store), лучше завернуть их в JSON.parse(), так браузер сможет распарсить их быстрее, и это тоже улучшит TTI: joreteg.com/blog/improving…
3. Про взаимодействие и UX.
Если использовать скелетон, а не спиннер, то пользователям кажется, что страница загружается быстрее: uxdesign.cc/what-you-shoul…
Полезно изучить, как пользователи переходят по страницам сайта, и использовать это знание для предварительной загрузки ресурсов. Допустим, с главной 80% идут на регистрацию, тогда можно заранее загрузить ресурсы и в фоне отрендерить эту страницу. caniuse.com/link-rel-prere…
С rel="prerender" нужно работать осторожно, так как это ускоряет следующую страницу для части пользователей за счёт загрузки доп ресурсов на текущей для всех. Не рекомендуется делать более одной ссылки с rel="prerender" на странице.
Используюя rel="preload" можно скачать и закешировать ресурсы, которые скоро понадобятся. В отличие от rel="prerender", они не будут исполнены (только скачаются). caniuse.com/link-rel-prelo…
Guess.js — экспериментальная библиотека, которая на основе данных гугл-аналитики предсказывает, на какую страницу дальше пойдёт пользователь, и динамически делает prerender/preload. github.com/guess-js/guess
Для Webpack есть preload-webpack-plugin, он решает проблему добавления ссылок на ресурсы с хешем в имени: npmjs.com/package/@vue/p…
Совсем немного про отзывчивость интерфейса:
Если в течение ~100мс после действия (клик по кнопке, нажатие на меню, фокусировка в инпуте и начало ввода текста и тд) пользователь не получил визуального подтверждения, ему кажется, что интерфейс тормозит
Поэтому важно не блокировать интерфейс при выполнении запросов к API и других операциях, и максимально быстро показать, что что-то произошло.
Есть паттерн Optimistic UI, согласно которому предполагается, что операция завершилась успехом, и показывает результат сразу по взаимодействию, ещё до того, как выполнен запрос/пришли данные. uxplanet.org/optimistic-100…
Особенно хорошо такой подход работает в случае с атомарными независимыми друг от друга операциями
С вами была Ирина Соколовская, и моя неделя в этом аккаунте подошла к концу. Вы классные, мне было с вами интересно, надеюсь и вам со мной тоже :)
Мой личный твиттер: @ierhyna
В реплаях соберу тред тредов из всего, о чем рассказала на этой неделе.
Всем доброй пятницы!
Вчера вечером мы поговорили про деньги и где их можно заработать, подробности вот в треде 👇
Ну и самая главная мысль: легких денег не бывает. Нет ни одной волшебной схемы, которая сделает тебя богатым. Путь к бабкам всегда труд
Труд не такой, что сутками пахать на износ на заводе — так много не заработаешь. Труд состоит в том, что ты должен потратить ГОДЫ, чтобы создать капитал. И эти годы ты должен быть сконцентрирован, не бросать то что начал, не верить в «схемы».
То же самое применимо к зарплате в IT. Хочешь 500к? Будь готов потратить несколько лет на получение опыта и экспертизы. Тебе придётся интересоваться всем что происходит. Можешь сидеть с 9до5, а после забывать про разработку, но тогда 500к не жди.
Фуф, ну и денёк сегодня выдался.
Как и обещал, давайте поговорим немного про бабки 💸
Все их любят, всем они нужны для того, чтобы влачить своё существование. Но где их взять, как сохранить и преумножить?
Пока я пишу тред кидайте свои варианты
Первое и самое очевидное — зарплата.
Вы меняете своё время и навыки на деньги. Все это делают, большинство только этим и живёт. У зарплаты есть такие свойства: она ограничена кол-вом часов в сутках, вашими умениями и часто геопозицией.
Мы можем работать N часов в сутки и получать M шекелей за час. M зависит от того сколько стоят ваши навыки на рынке в вашей местности. Также зарплата может резко сократиться до 0 если вы заболеете, получите неисправимую травму или больше будете не нужны на рынке.
Всем доброе утро ☕️
Чем ближе к пятнице, тем расслабленнее разговоры)
Сегодня побуду бабкой-предсказательницей и буду предсказывать куда будет двигаться разработка в ближайшем будущем 🔮
А также хочу поговорить про денежки: зарплаты, сайд-проекты и инвестиции
🔮 Предсказание первое 🔮
Разработка будет становится проще и проще, особенно для непрограммистов. No-code тулзы станут настолько мощными, что можно будет создать ПОЧТИ любой софт без написания кода.
Компиляторы тоже станут умнее. Любой говнокод будут превращать в нормальный
🔮Предсказание второе🔮
Первое предсказание приведёт к тому, что инструменты и компьютеры станут настолько сложными, что мало кто будет понимать как они работают. Единицы сохранять знание, а может и вообще никто. Тогда сложная техника станет техно-культом/религией
Отличный вопрос!
И у меня есть ответ: постоянно получаю вакансии в зарубежные компании, устроился в американскую компанию через один интересный сайт и не я один :)
Вот небольшой список ресурсов где можно найти вакансию за рубежом 🧵
Первое что вам нужно сделать - заполнить профиль на LinkedIn. В большинстве случаев вы начнёте получать предложения о работе при наличии релевантного опыта. Часто эти предложения включают в себя работу на зарубежную компанию или релокацию 🧵
За рубежом (я знаю про США, возможно в Европе тоже) есть следующий тренд: очень много выпускников из универов которые могут пойти стажёрами и очень много сеньоров, которые хотят быть СТО и не хотят кодить 🧵
Господа, пожалуйста не воспринимайте всерьёз то что написано в этом треде. Нормальная инфа про чистые функции скоро подъедет, сегодня очень загруженный день на работе, но вы держитесь 💪
Если кому есть что сказать - велком в реплаи
Итак, чистые функции. Чистой называется такая функция, которая: 1. Всегда возвращает один и тот же результат при одних и тех же аргументах; 2. Не оказывает никакого влияния на внешний мир - никакого IO, работы с глобальными переменными, бд итд
Выполнив оба этих требования вы получаете чистую функцию. Нарушив хотя бы одно из них, функция теряет некоторые/все свойства, которые делают ее удобной в использовании.
Что за свойства?