Size: a a a

Иван Акулов про разработку

2021 August 29
Иван Акулов про разработку
🙅 Как не надо оптимизировать сайт под SEO: https://twitter.com/colinbendell/status/1431284803630940161
источник
Иван Акулов про разработку
Lighthouse не помогает в SEO
Самое забавное, что эта оптимизация не поможет вообще никак. Google не использует Lighthouse, чтобы ранжировать сайты. Вместо этого Google использует данные, которые он собирает с реальных устройств посетителей. Эти данные видны в Search Console.

Разница почти в каждой метрике
На практике это влияет ещё на две вещи:

— CLS. CLS в Lighthouse считается очень ограниченно — без прокрутки страницы и только до конца загрузки. Получается, что если в середине страницы есть изображение, которое скачет при загрузке, Lighthouse этот скачок не словит. А часть пользователей прокрутит до изображения и словит — и CLS из-за них вырастет.

Поэтому CLS в Search Console часто выше, чем в Lighthouse, и оптимизировать его нужно лучше.

— FID/TTI/TBT. FID, TTI и TBT отвечают на вопрос «насколько моя страница лагает из-за JavaScript-а?» Но каждая метрика отвечает по-разному. Для ранжирования сайтов важен только FID, и обычно он хороший, даже когда TTI и TBT плохие.

Поэтому не пытайтесь оптимизировать JS или third parties, если вы пытаетесь стать лучше в поиске. TTI/TBT станут лучше, но в поиске это не поможет.

Короче, Search Console
Если оптимизируете сайт под SEO, смотрите только на Core Web Vitals в Search Console: https://search.google.com/search-console/core-web-vitals/summary
источник
2021 August 30
Иван Акулов про разработку
Оп, а вот ещё кейс, где LCP искуственно занижается (и разбор, как именно): https://twitter.com/geekybiz/status/1429746730258427911
источник
2021 September 14
Иван Акулов про разработку
Разница между componentDidMount и useEffect в одной картинке

(= componentDidMount всегда вызывается в текущем кадре, а useEffect — обычно в начале следующего)
источник
Иван Акулов про разработку
Почему это важная разница? Потому что это помогает избежать принудительного перевычисления стилей.

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

Что за принудительное перевычисление? Это частый перформанс-антипаттерн. См. https://kellegous.com/j/2013/01/26/layout-performance/ и https://gist.github.com/paulirish/5d52fb081b3570c81e3a.

А что с useLayoutEffect? useLayoutEffect вызывается там же, где и componentDidMount — в текущем кадре. Из-за этого код в useLayoutEffect тоже может вызвать принудительное перевычисление. Это главная причина, по которой React не рекомендует использовать useLayoutEffect (если вы только не знаете наверняка, зачем он вам).

Сносочка. useEffect обычно вызывается в следующем кадре — но не всегда. Если у React запланировано несколько рендеров подряд, он будет вызывать useEffect сразу перед следующим рендером, не дожидаясь окончания кадра. См. документацию → «it’s guaranteed to fire before any new renders»
источник
2021 September 17
Иван Акулов про разработку
Убрать бандл
Оказывается, в Next.js можно убирать бандл с отдельных страниц недокументированным флагом unstable_runtimeJS:

/* pages/my-page.js */
export const config = {
 unstable_runtimeJS: false
}

export default () => <h1>My page</h1>


А если у вас Gatsby, бандл убирается со всех страниц сразу плагином gatsby-plugin-no-javascript (+ utils).

Профит в том, чтобы не грузить React зря на страницах, где нет никакой интерактивности. На 3perf.com, например, такая оптимизация помогла поднять Lighthouse c 65 до 90 баллов
источник
2021 September 23
Иван Акулов про разработку
Когда не надо useSelector

Обнаружил интересную оптимизацию с React и Redux.

Обычно, чтобы в React получить данные из Redux, рекомендуется использовать useSelector. Например, вот так можно получить user id:

const userId = useSelector(state => state.selectedUser.id)

useSelector вызывает перерисовку компонента каждый раз, когда данные меняются. Это полезно — если пользователь поменялся, мы хотим, чтобы и его аватарка перерисовалась:
источник
Иван Акулов про разработку
источник
Иван Акулов про разработку
Но что, если мы используем userId не в самом компоненте, а в обработчике события? Тогда компонент будет перерисовываться зря. userId будет меняться, но DOM будет оставаться таким же:
источник
Иван Акулов про разработку
источник
Иван Акулов про разработку
Если компонент <ChangeUserAvatarButton /> дорогой, а выбранный пользователь меняется часто, это может быть проблемой.

Так вот. Оказывается, что когда какой-то элемент стейта нужен только в обработчике события, useSelector без проблем заменяется на useStore:
источник
Иван Акулов про разработку
источник
Иван Акулов про разработку
useStore вернёт стор — и всё. Он не будет извлекать какие-то конкретные поля из стора. Он не будет перерисовывать компонент, когда что-то меняется.

Когда пользователь нажмёт на кнопку, нам останется только достать актуальный userId прямо из store.getState(). Никаких лишних ререндеров.

🔗 Документация: https://react-redux.js.org/api/hooks#usestore
источник
2021 September 28
Иван Акулов про разработку
Классно и подробно про текущий статус React 18, Suspense и Server Components:
— что уже сделано
— что в процессе
— и что ещё непонятно и исследуется

https://github.com/reactwg/react-18/discussions/98#discussioncomment-1318753
источник
2021 October 01
Иван Акулов про разработку
Как Chrome загружает и выполняет
— <script> в <head>
— <script async>
— <script defer>
— <script> в <body>
и другие вариации скриптов:

https://addyosmani.com/blog/script-priorities/
источник
2021 October 20
Иван Акулов про разработку
Fontsource

Наткнулся на Fontsource и мгновенно влюбился: https://fontsource.org

Fontsource позволяет устанавливать через npm шрифты, которые есть в Google Fonts. Это ощутимо быстрее и улучшает LCP:
— Google Fonts требует подключить CSS со стороннего сервера (fonts.googleapis.com)
— Чтобы загрузить стили с fonts.googleapis.com, браузеру нужно сначала установить соединение с этим сервером. Это долго — 400-500 мс на 4G
— А пока браузер не скачает стили, страница будет оставаться невидимой

А вот если подключить шрифт из npm-пакета Fontsource, то стили и шрифт будут на том же сервере и загрузятся быстрее
источник
Иван Акулов про разработку
Кайф Fontsource ещё в том, что он, как и Google Fonts, сабсеттит шрифты по наборам символов (латиница, кириллица и т.д.). Благодаря этому, если сайт целиком англоязычный, то весь файл шрифта скачиваться не будет — только символы латиницы.

Раньше, когда я перемещал шрифты из Google Fonts на свой сервер, делать такую нарезку приходилось вручную (и это было больно)
источник
2021 October 22
Иван Акулов про разработку
​​Попробовал Typekit (сервис веб-шрифтов Adobe) и официально заявляю, что они — проклятье перформанса. Никогда не используйте их. Обходите их стороной. Если случайно закоммиттите их, напечатайте коммиты на бумаге и сожгите.

Что это
Typekit — это как Google Fonts, но от Adobe. Вы регистрируетесь, выбираете шрифты, получаете ссылку на стили, подключаете стили, радуетесь (наивные).

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

Когда вы выбираете шрифты, Typekit даёт вам ссылку на стили, которые нужно подключить — например, https://use.typekit.net/mzg2ufm.css. Эти стили живут на стороннем сервере (use.typekit.net), и это плохо — браузеру нужно потратить кучу времени на то, чтобы подключиться к этому серверу. Вот, например, в этом тесте стили со своего домена (запрос 2) скачиваются за 200 мс, а стили с домена Typekit — за 700. 500 мс мы просто устанавливаем соединение:
источник
Иван Акулов про разработку
​​​​Но ладно, с этим можно жить. Google Fonts, например, тоже отдают стили со стороннего сервера.

Но знаете, что стили Typekit делают в первую очередь, как только загрузятся? Они импортируют другие стили. Ааааа!
источник
Иван Акулов про разработку
​​​​То есть браузер такой: «о, чётко, все <link rel="stylesheet"> загрузились, можно отрендерить страницу». А Typekit ему такой: «пха, погоди, у меня тут ещё одни стили, не хочешь и их загрузить сначала?» И всё — вместо того, чтобы загрузить всё за раз, браузер загружает новые стили по второму кругу.

При этом — вы видите, откуда Typekit загружает другую таблицу стилей? С ещё одного стороннего домена. То есть браузер только что потратил 500 мс на подключение к use.typekit.net — и теперь тратит ещё 500 мс на подключение к p.typekit.net. Напоминаю, страница всё ещё не видна, потому что стили всё ещё не загрузились.
источник