Привет! Сегодня поговорим про оптимизации, что влияет на метрики, расскажу про best practices и случаи из жизни :)
Выделю три основные направления возможных оптимизаций:
- размеры бандлов и их доставка
- загрузка и отрисовка страницы
- взаимодейстивие со страницей, отзывчивость, UX
1. Про бандлы и доставку:
Кажется очевидным, но почему-то часто об этом забывают:
- включите сжатие gzip/brotli для ресурсов
- используйте в вебпаке хеш от контента в имени файла, и включите кеширование на подольше (у нас на месяц)
Тоже очевидно, но всё же, убедитесь, что вебпак собирает бандлы в продакшен-режиме с включенной опцией minimize: Image
Следующим шагом можно настроить в вебпаке разбивку на чанки. Чтобы это сделать, неплохо для начала проанализировать, из чего состоит итоговый бандл. Например, с помощью 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…
Дать файлам чанков человеко-читаемые имена поможет волшебный комментарий для вебпака: Image
Хорошим способом сократить объем кода, скачиваемого при первой загрузке React приложения, будет импортировать с lazy() все компоненты, с которыми пользователь не взаимодействует сразу: модалки, скрытые компоненты, и подобное.
Некоторые npm пакеты могут существенно увеличить объем бандла кодом, который никогда не будет использован. Например, moment.js по-умолчанию включает все возможные локали, а lodash — все хелперы.
Исключить лишние локали из moment.js можно через moment-locales-webpack-plugin,
github.com/iamakulov/mome…, IgnorePlugin или ContextReplacementPlugin github.com/jmblog/how-to-…
Про загрузку только необходимых функций lodash, можно почитать тут: azavea.com/blog/2019/03/0…
Про загрузку, отрисовку и взаимодейстивие со страницей продолжу завтра
2. Про загрузку и отрисовку страницы:
Чтобы разобраться в том, как оптимизировать отрисовку, нужно понимать, как браузер рендерит страницу.
Пара ссылок:
1)developers.google.com/web/fundamenta…,
2)medium.com/jspoint/how-th…
Блокируют отрисовку страницы:
- Стили, подключенные без атрибута 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%! Image
Ещё немного про шрифты:
- формата woff2 достаточно в большинстве случаев (caniuse.com/?search=woff2);
- подключайте шрифт с preload;
- используйте font-display: swap; Image
Про изображения:
- указывайте width/height, так браузер заранее зарезервирует место для картинок
- для контентных картинок — атрибут loading="lazy" (caniuse.com/loading-lazy-a…) для нативной загрузки по скроллу (полифил: github.com/mfranzke/loadi…)
Для контентных картинок можно использовать тег picture (developer.mozilla.org/en-US/docs/Web…), чтобы, например, загружать более легкие изображения на маленьких экранах. Плагин: responsive-loader (npmjs.com/package/respon…).
Совет от кэпа: убедитесь, что картинки минимизованы и имеют адекватные размеры! Особенно, если картинки могут загружать пользователи. В одном нашем сервисе мы сэкономили 10мб просто на том, что привели изображения к ширине 1024px и качеству 85% ¯\_(ツ)_/¯
Кулстори про клиентский и серверный рендеринг. Есть мнение, что рендерить страницу на сервере быстрее, чем на клиенте. Поэтому мы выпилили реакт на одной из статичных страниц, и переписали её на чистом html, который собирается через Django на бэке (Django там уже был) ->
Постепенно к странице появлялись всё новые требования: сначала кастомизации в зависимости от тарифного плана и страны пользователя, а через год — от нескольких десятков параметров. Настройки делали на бэке условиями в темплейте, в итоге time to first byte составил 2 сек
Поддерживать это стало очень сложно, решили снова переписать на реакте. Страница стала отдаваться за 200мс, но выросли TTI и CLS (август-сентябрь на графике): Image
Тогда придумали к̶о̶с̶т̶ы̶л̶ь изящное решение: для видимой части сверстали скелетон (штуку как на картинке) и заинлайнили его стили в <style>. Поместили этот код внутри тега, куда рендерится реакт, чтобы он заменялся на реактом на готовую страницу с контентом. Image
Если нужно передать через шаблон данные с сервера на клиент (например, initial state для redux store), лучше завернуть их в JSON.parse(), так браузер сможет распарсить их быстрее, и это тоже улучшит TTI:
joreteg.com/blog/improving…
3. Про взаимодействие и UX.
Если использовать скелетон, а не спиннер, то пользователям кажется, что страница загружается быстрее:
uxdesign.cc/what-you-shoul… Image
Полезно изучить, как пользователи переходят по страницам сайта, и использовать это знание для предварительной загрузки ресурсов. Допустим, с главной 80% идут на регистрацию, тогда можно заранее загрузить ресурсы и в фоне отрендерить эту страницу.
caniuse.com/link-rel-prere… Image
С rel="prerender" нужно работать осторожно, так как это ускоряет следующую страницу для части пользователей за счёт загрузки доп ресурсов на текущей для всех. Не рекомендуется делать более одной ссылки с rel="prerender" на странице.
Используюя rel="preload" можно скачать и закешировать ресурсы, которые скоро понадобятся. В отличие от rel="prerender", они не будут исполнены (только скачаются).
caniuse.com/link-rel-prelo… Image
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…
Особенно хорошо такой подход работает в случае с атомарными независимыми друг от друга операциями
Как реализовать Optimistic UI с Apollo GraphQL:
apollographql.com/docs/react/per…
Как реализовать Optimistic UI с React Query:
react-query.tanstack.com/guides/optimis…

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with jsunderhood

jsunderhood Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @jsunderhood

21 Mar
С вами была Ирина Соколовская, и моя неделя в этом аккаунте подошла к концу. Вы классные, мне было с вами интересно, надеюсь и вам со мной тоже :)
Мой личный твиттер: @ierhyna
В реплаях соберу тред тредов из всего, о чем рассказала на этой неделе.
Опросы о том, насколько аудитория андерхуда знакома с темой веб-производительности:
Read 6 tweets
5 Feb
Всем доброй пятницы!
Вчера вечером мы поговорили про деньги и где их можно заработать, подробности вот в треде 👇
Ну и самая главная мысль: легких денег не бывает. Нет ни одной волшебной схемы, которая сделает тебя богатым. Путь к бабкам всегда труд
Труд не такой, что сутками пахать на износ на заводе — так много не заработаешь. Труд состоит в том, что ты должен потратить ГОДЫ, чтобы создать капитал. И эти годы ты должен быть сконцентрирован, не бросать то что начал, не верить в «схемы».
То же самое применимо к зарплате в IT. Хочешь 500к? Будь готов потратить несколько лет на получение опыта и экспертизы. Тебе придётся интересоваться всем что происходит. Можешь сидеть с 9до5, а после забывать про разработку, но тогда 500к не жди.
Read 4 tweets
4 Feb
Фуф, ну и денёк сегодня выдался.
Как и обещал, давайте поговорим немного про бабки 💸
Все их любят, всем они нужны для того, чтобы влачить своё существование. Но где их взять, как сохранить и преумножить?
Пока я пишу тред кидайте свои варианты
Первое и самое очевидное — зарплата.
Вы меняете своё время и навыки на деньги. Все это делают, большинство только этим и живёт. У зарплаты есть такие свойства: она ограничена кол-вом часов в сутках, вашими умениями и часто геопозицией.
Мы можем работать N часов в сутки и получать M шекелей за час. M зависит от того сколько стоят ваши навыки на рынке в вашей местности. Также зарплата может резко сократиться до 0 если вы заболеете, получите неисправимую травму или больше будете не нужны на рынке.
Read 19 tweets
4 Feb
Всем доброе утро ☕️
Чем ближе к пятнице, тем расслабленнее разговоры)
Сегодня побуду бабкой-предсказательницей и буду предсказывать куда будет двигаться разработка в ближайшем будущем 🔮
А также хочу поговорить про денежки: зарплаты, сайд-проекты и инвестиции
🔮 Предсказание первое 🔮
Разработка будет становится проще и проще, особенно для непрограммистов. No-code тулзы станут настолько мощными, что можно будет создать ПОЧТИ любой софт без написания кода.

Компиляторы тоже станут умнее. Любой говнокод будут превращать в нормальный
🔮Предсказание второе🔮
Первое предсказание приведёт к тому, что инструменты и компьютеры станут настолько сложными, что мало кто будет понимать как они работают. Единицы сохранять знание, а может и вообще никто. Тогда сложная техника станет техно-культом/религией
Read 7 tweets
3 Feb
Отличный вопрос!
И у меня есть ответ: постоянно получаю вакансии в зарубежные компании, устроился в американскую компанию через один интересный сайт и не я один :)
Вот небольшой список ресурсов где можно найти вакансию за рубежом 🧵
Первое что вам нужно сделать - заполнить профиль на LinkedIn. В большинстве случаев вы начнёте получать предложения о работе при наличии релевантного опыта. Часто эти предложения включают в себя работу на зарубежную компанию или релокацию 🧵
За рубежом (я знаю про США, возможно в Европе тоже) есть следующий тренд: очень много выпускников из универов которые могут пойти стажёрами и очень много сеньоров, которые хотят быть СТО и не хотят кодить 🧵
Read 6 tweets
3 Feb
Господа, пожалуйста не воспринимайте всерьёз то что написано в этом треде. Нормальная инфа про чистые функции скоро подъедет, сегодня очень загруженный день на работе, но вы держитесь 💪
Если кому есть что сказать - велком в реплаи
Итак, чистые функции. Чистой называется такая функция, которая:
1. Всегда возвращает один и тот же результат при одних и тех же аргументах;
2. Не оказывает никакого влияния на внешний мир - никакого IO, работы с глобальными переменными, бд итд
Выполнив оба этих требования вы получаете чистую функцию. Нарушив хотя бы одно из них, функция теряет некоторые/все свойства, которые делают ее удобной в использовании.
Что за свойства?
Read 12 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!

Follow Us on Twitter!