Использование ленивых загружаемых компонентов может привести к двойственности CLS и медленным соединениям

Использование ленивых загружаемых компонентов может привести к двойственности CLS и медленным соединениям

6 апреля 2022 г.

Когда вы оптимизируете свое веб-приложение, ваша цель — сделать его более удобным для пользователя; обычно это означает «быстрее» за счет передачи и анализа меньшего количества данных. Но будьте осторожны: одно и то же веб-приложение может вызвать кумулятивное смещение макета (CLS) на более медленных соединениях, но работать без CLS на более быстрых соединениях.


Если вы хотите напомнить о Core Web Vitals, я объяснил их с помощью GIF-файлов в [этом посте] (https://wicki.io/posts/2021-07-core-web-vitals/).


==TL;DR:== ==более медленные соединения могут привести к CLS при ленивой загрузке компонентов, которые вы не увидите при подключении к Wi-Fi.==


== Либо вообще не ленитесь загружать компонент, либо дождитесь загрузки и монтирования js-файла. ==


Двойственность


Медленное или быстрое соединение: одно и то же веб-приложение с разными CLS.


Мы предполагаем, что веб-приложение загружает то же самое при более медленных соединениях, просто медленнее. К сожалению, это не всегда так с ленивыми загружаемыми компонентами.


С ленивыми загружаемыми компонентами мы имеем дело с двумя асинхронностями:


  • ответы асинхронного API (JSON)

  • Компоненты асинхронной ленивой загрузки (JS)

Что, если ответы API (1) быстрее, чем динамически загружаемый JS (2)? Что, если вы лениво загрузите компонент, который находится в середине вашего веб-контента? Ответ на эти вопросы вы видите на снимке экрана выше: Google накажет вас CLS.


Измерение CLS


Я видел много путаницы в отношении Core Web Vitals, особенно CLS.


В отличие от других Core Web Vitals, CLS постоянно измеряется и кумулятивно добавляется к баллу. Для классического веб-приложения SPA это означает, что Google будет сохранять оценку CLS для каждого маршрута.


CLS имеет следующие характеристики:


  • После каждого изменения маршрута CLS сбрасывается на 0

  • После любого взаимодействия с пользователем вы получаете льготный период в 500 мс, когда CLS не принимается во внимание.

Измерения реальных пользователей: пользователи Chrome отправляют показатели Core Web Vitals напрямую в Google. Это не робот Googlebot, который фиксирует эти показатели при сканировании сайта.


Эти реальные пользовательские измерения собираются как [данные поля] (https://web.dev/lab-and-field-data-differences/#field-data) и передаются в [отчет CrUX] Google (https://developers. google.com/web/tools/chrome-user-experience-report).


Это означает, что вам нужно учитывать реальный мир:


  • Если у вас много трафика из Индии, но ваши серверы находятся на другом конце света, вероятно, пострадает ваш LCP (Largest Contentful Paint).

  • Если у вас много трафика из Китая, вполне вероятно, что некоторые сервисы заблокированы китайскими провайдерами и не загружаются. Это может привести к появлению нежелательных CLS в вашем контенте.

Решения


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


  • Запросы API все еще загружаются?

  • асинхронные компоненты все еще загружаются?

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


Решение №1: вообще не откладывайте загрузку компонентов


Самым быстрым и наименее подверженным ошибкам решением будет передача компонентов с отложенной загрузкой. В большинстве случаев сэкономленные килобайты за счет отложенной загрузки не оправдывают CLS, который она может вызвать. Если ваш бюджет позволяет, используйте это решение.


Предположим, у нас есть веб-приложение Vue с 10% зарегистрированных пользователей.


```машинопись


функция рендеринга () {


// не всем пользователям требуется скачивать и отображать HugeComponent


если (вошел в систему) {


вернуть <ОгромныйКомпонент/>;


Без разделения кода мы отправили бы JS <HugeComponent> 90% пользователей, которым он не нужен. Это может повлиять на LCP и FID.


При разделении кода мы упаковываем JS-код <HugeComponent> в фрагмент Additional-comps.js и отправляем его по сети только тогда, когда это необходимо.


```машинопись


// без разделения кода


импортировать HugeComponent из '@/components/HugeComponent';


// с разделением кода


const HugeComponent = () => (ожидание импорта(


/ webpackChunkName: "дополнительные-компы" /


'@/компоненты/HugeComponent')


).По умолчанию;


Есть два критерия, которые помогут вам решить, следует ли лениво загружать компонент или нет:


  • размер <HugeComponent>

  • как часто <HugeComponent> будет отображаться для пользователей

Если вы пришли к выводу, что ваш бюджет на производительность ограничен и вам нужно лениво загружать компонент, см. решение № 2.


Решение №2: Дождитесь загрузки и монтирования компонента


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


Подождать, пока асинхронные компоненты будут лениво загружены и смонтированы, может быть сложно. Вам нужно визуализировать компонент, но монтирование происходит позже. Вот суть того, как это можно сделать.


```машинопись


функция Родитель({ isLoggedIn }) {


const [isLoading, setLoading] = useState (false);


// важно: скрыть дочерние элементы только с display: none.


// если бы мы использовали if-else, мы бы никогда не загрузили ленивый загружаемый компонент;


// и тогда мы бы никогда не изменили isLoading с его обратным вызовом.


const styles = { display: isLoading? 'нет' : 'заблокировать' };


вернуть (


{/ HugeComponent загружается лениво, потому что не всем пользователям он нужен /}


(isLoggedIn && <HugeComponent


стиль = { стили }


Mounted={() => setLoading(true)}


{/ отображать скелетный элемент во время загрузки /}


(isLoading &&

)


function HugeComponent (реквизит: { смонтирован: () => void}) {


const [dataA, setData] = useState (null);


useEffect (асинхронный () => {


константный результат = ожидание lib.request();


установить данные (результат);


// сообщаем родительскому компоненту, что все готово для полного рендеринга


реквизит.mounted();


вернуть (/ ... /);


Если бы мы не использовали display: hidden для состояния загрузки в <HugeComponent>, мы бы никогда не инициировали загрузку асинхронного компонента. Таким образом, строка 28 никогда не будет достигнута, а состояние «isLoading» навсегда останется «ложным».


Заключение


Если вы потеряли зеленые URL-адреса в Google Search Console из-за CLS и не можете воспроизвести их самостоятельно, попробуйте отладить свое веб-приложение с более медленным соединением.


Поэтому, если вы используете ленивые загружаемые компоненты, высока вероятность, что вы можете стать жертвой двойственности CLS.


Если вы нашли этот пост интересным, оставьте ❤️ в [этом твите] (https://twitter.com/zwacky/status/1508354371205185537) и рассмотрите возможность подписаться на мое 🎢 путешествие о #webperf, #документальных книгах, #buildinpublic и #frontend имеет значение в Твиттере.



Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE