Почему мы все еще работаем с HTTP/2 в 2022 году

HTTP/2 вышел! CDN — это горячо!

Возможно, вы слышали о HTTP/2 и его мультиплексировании активов, а также о преимуществах, которые он может принести вашему проекту, позволяя загружать больше активов одновременно, уменьшая необходимость в массивных пакетах активов и тем самым снижая отток кэша.

Все вышесказанное — правда. HTTP/2 сотворил чудеса с загрузкой активов. Однако HTTP/2 не является универсальным решением, позволяющим отказаться от текущего набора фронтенд-пакетов и использовать только CDN.

Однако проблема в том, что вы теряете ряд преимуществ, которые можно получить, используя frontend bundler. Для выполнения этого упражнения мы рассмотрим Shoelace.

Shoelace — это проект с открытым исходным кодом, который использует веб-компоненты и переменные CSS для создания целостной системы дизайна вашего веб-приложения. Этот пример не говорит о том, что Shoelace работает или не работает, а просто используется в качестве примера того, где CDN падают. Кроме того, вы должны использовать Shoelace, это очень крутой проект!

Приступим

Самый простой путь установки Shoelace — это импорт из JS CDN, например jsdelivr.

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.78/dist/themes/light.css" />
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.0.0-beta.78/dist/shoelace.js"></script>
Войдите в полноэкранный режим Выход из полноэкранного режима

Давайте посмотрим на созданный сетевой график.

Не погружаясь слишком глубоко, можно сказать, что Shoelace поставляет базовый «модуль», который затем использует ряд общих блоков, генерируемых ESBuild. Поэтому, когда запрашивается <script src="${cdn}@{versionNumber}/dist/shoelace.js", то запрашиваются чанки, которые также находятся на том же пути, и эти чанки могут импортировать другие чанки, а затем эти чанки импортируются. Вы можете видеть, как при наличии глубоко вложенного набора «чанков» это может быстро увеличить время отклика и создать эффект «водопада», который мы видим здесь. Водопад» называется так потому, что каждый запрос зависит от предыдущего запроса. Представьте, что у вас несколько редиректов на одном маршруте.

redirect_to "/foo" -> redirect_to "/bar" -> redirect_to "baz"

Это тот же самый эффект. Вы не знаете, что вам нужен следующий актив, пока не запросите этот актив. Или, в данном случае, файл javascript.

Устранение водопада

Введите <link rel="modulepreload">.

https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/modulepreload

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

Давайте рассмотрим https://jspm.org/, которая является CDN по умолчанию, используемой с новыми Rails importmaps.

Я создал граф «modulepreload» для Shoelace-beta.78 и загрузил его в свой index.html.

https://generator.jspm.io/#U2NjYGBkDM7IT81JTE5VyMwtyC8qyU0sYHAohorpFpdU5qTqw7gORnoGega6SakliXrmFgB/h42GPwA

Вы можете видеть, что этот «водопад» немного меньше, и начальные «куски» запрашиваются параллельно, что уменьшает эффект «водопада»! Предварительная загрузка модулей — это хорошо, и она отлично работает в Shoelace! Однако, они добавляют много накладных расходов, поскольку каждый раз, когда вы обновляете версию Shoelace, вам приходится генерировать новый граф предзагрузки.

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

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

Неиспользуемая подстановка импорта

В традиционных модулях JavaScript, импортируемых из CDN, нет никакого древовидного импорта. Что вы запрашиваете, то и получаете. Такие сборщики, как Parcel / Rollup / Webpack / Vite, могут статически анализировать любой код, который вы импортируете, и избавляться от всех путей кода, которые не используются. CDN не имеют такой привилегии, поскольку у них нет возможности анализировать ваш конечный код.

Вот очень простой пример того, как работает древовидная система на основе зависимостей.

export function doTheRoar () { return "roar" }

export function doTheMeow () { return "meow" }
Вход в полноэкранный режим Выйти из полноэкранного режима

Затем в коде нашего приложения мы сделаем примерно следующее:

import * as doIt from "./my-package"
console.log(doIt.doTheRoar())
Войти в полноэкранный режим Выйти из полноэкранного режима

В приведенном выше случае пакетник избавится от функции «doTheMeow» и отправит только «doTheRoar» в наш окончательный производственный пакет, тем самым уменьшив количество JavaScript, которое мы отправляем. Если мы используем CDN, doTheRoar и doTheMeow всегда будут поставляться, даже если они не используются.

Подъем объема

Пока мы говорим об эффективности, мы можем поговорить о «подъеме области действия». Поднятие области видимости эффективно следующим образом из документации Parcel:

…объединяет модули в одну область видимости, когда это возможно, вместо того, чтобы оборачивать каждый модуль в отдельную функцию. Это называется «поднятие области видимости». Это помогает сделать минификацию более эффективной, а также улучшает производительность во время выполнения, делая ссылки между модулями статическими, а не динамическими поисками объектов.

https://parceljs.org/features/scope-hoisting/

Scope hoisting помогает минимизировать объем JavaScript, который мы поставляем, а также повышает производительность. По-моему, звучит неплохо!

Разбивка, разделение кода и дублирование кода

Пакеты для фронтенда позволяют нам «разбить» или «разделить код» наших пакетов и поставлять меньшие пакеты, используя преимущества HTTP/2! Мы можем разделять код различными способами, о которых я не буду говорить, но суть в том, что вы можете это делать. Разделение кода позволяет нам создавать оптимизированные куски.

Из документации Parcel:

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

https://parceljs.org/features/code-splitting/

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

Разбивка на куски/разделение также позволяет говорить о дублировании зависимостей. С помощью CDN вы можете легко увеличить количество импортируемого JavaScript, если импортируете похожие, но немного отличающиеся по версии зависимости.

Например, Shoelace импортирует Lit, и допустим, вы хотите использовать Lit в своем проекте. Из-за того, что Shoelace импортирует Lit внутри CDN, чтобы сделать его самодостаточным, вы не получаете доступа к Lit, а значит, вам придется импортировать библиотеку заново самостоятельно, что означает, что она не является «общей» зависимостью.

https://unpkg.com/browse/@shoelace-style/shoelace@2.0.0-beta.78/dist/chunks/chunk.WWAD5WF4.js

С помощью frontend bundlers мы можем легко подключиться к lit и самостоятельно собрать исходники Shoelace, что позволит нам поставлять меньший конечный пакет за счет отсутствия дублирования зависимостей.

Совместное использование кэша на разных сайтах и доменах

Последнее замечание касается кросс-оригинального обмена ресурсами. Распространенной фразой раньше была следующая

«Если вы импортируете jquery на сайт A из CDN и импортируете jquery на сайт B из того же CDN, вы не несете затрат, а браузер использует кэшированную версию».

Теперь это не так.
https://twitter.com/seldo/status/1486122838801063938

Что это изменение означает для вас? Если ваши сайты находятся на современном хостинге, который предоставляет CDN и поддерживает HTTP/2, вам следует отказаться от услуг третьих сторон и отправлять все ресурсы самостоятельно. Полагаясь на ресурсы третьих сторон, вы не получите никакой пользы в 2020 году.

Хотя последний пункт может быть спорным, особенно для тех, кто размещает свои собственные ресурсы на маршрутизаторах, не поддерживающих HTTP/2 (смотрим на вас, Heroku), важно отметить, что доставка зависимостей от первой стороны предлагает гораздо больше контроля и может привести к лучшей производительности, поскольку не нужно делать дополнительный HTTP-шарп к третьей стороне.

Вот и все, друзья!

Хотя HTTP/2 предлагает тонну преимуществ в производительности, особенно в отношении загрузки активов. Это не означает, что мы не можем найти преимущества в объединении наших приложений. В конце концов, если вы оценили все варианты и сделали то, что лучше всего подходит для вашего проекта, вот что действительно важно.

Оцените статью
devanswers.ru
Добавить комментарий