July 23, 2021

Создание фреймворков JavaScript для завоевания eCommerce

Было время, когда я никогда бы не подумал, что нужно писать такую статью. Если бы вы спросили кого-нибудь, как работал веб-сайт даже 10 лет назад, ответ был бы довольно простым. Сайт состоит из набора HTML-документов, которые находятся в определенных местах (URL-адресах), каждый из которых описывает способ отображения страницы и предоставляет ссылки для перехода на дополнительные страницы. Для запроса и отображения этих страниц используется веб-браузер.

Но за последние 10 лет наши разработки для Интернета значительно изменились. Парадигма изменилась настолько, что теперь, когда одностраничные приложения (SPA) становятся повсеместным продуктом, это традиционное многостраничное приложение (MPA) требует объяснения.

Когда я говорю об этом, я обнаруживаю, что многие разработчики JavaScript не понимают разницы и того, насколько глубокое влияние она оказывает. Как такие фреймворки, как Marko, Astro, Elder или Qwik, представляют собой совершенно другую архитектуру, чем Next.js, Nuxt.js или SvelteKit.

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

Состояние фронтенда JavaScript в 2021 году

Подавляющее большинство JavaScript Frameworks разработаны для того, чтобы помочь вам сделать то, что мы называем одностраничными приложениями (SPA). React, Vue, Ember, Preact, Svelte, Solid, и так далее. SPA - это простое приложение, в котором весь опыт обслуживается с одной страницы, отправленной с сервера (или CDN). Эта характеристика сохраняется в метафреймворках, построенных на их основе, таких как Next, Nuxt, Gatsby, SvelteKit, Remix, Blitz и т.д..

Определяющей чертой является то, что они построены на основе маршрутизации на стороне клиента. То есть браузер обрабатывает навигацию после первоначальной загрузки страницы, не отправляя запросы для получения HTML-страницы на сервер. Затем JavaScript повторно отображает часть страницы. Возможно на сервере тоже используется маршрутизация, но приложение работает через один вход.

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

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

Рендеринг на стороне сервера в помощь?

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

Кроме того, его может быть сложно настроить и разместить для различных сред развертывания. Одним из простых решений является генерация статических сайтов. Мы можем использовать серверный рендеринг фреймворка для предварительного рендеринга статических HTML-страниц.

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

Но все же есть несколько проблем. Во-первых, статическая генерация не подходит для динамического контента. Конечно, нет ничего лучше предварительно отрендеренной страницы, но если страница должна настраиваться под конкретного человека, включать A/B-тестирование различных продуктов и т.д., комбинаторика быстро становится непомерно дорогой. Бывают ситуации, когда это нормально, и решения рассматривают возможность параллельного предварительного рендеринга 10 тысяч страниц, но для динамического контента это просто не может быть актуальным без больших затрат.

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

Сейчас мы видим, что эти фреймворки позволяют отключить JavaScript на определенных страницах, но это, по сути, все или ничего. Это удобно, но мы можем сделать гораздо лучше, если будем знать, что оптимизируем для быстрой отрисовки (First Paint) и быстрой интерактивности (Time to Interactivity).

Это действительно вызывает вопрос. Устраивает ли нас это?

Возвращение многостраничных приложений

Что же дает просмотр приложений как набора отдельных страниц? Большую часть содержимого страницы никогда не нужно отображать в браузере.

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

Я не говорю про отсутствие JavaScript (хотя это может быть и так), просто его станет гораздо меньше. Сайт, который написан как одно большое приложение достаточно сложен. Разделение кода здесь не спасает. Если страница имеет одну одну входную точку, один корень, который отображается сверху вниз, как мы можем рассматривать такие страницы независимо? Мы можем обрезать "неиспользуемые ветви, но не ствол".

Очень немногие фреймворки оптимизированы для построения одного большого приложения. Когда у вас есть цепочки пропсов, проходящие через дерево компонентов вниз, трудно разделить их на части. На самом деле у вас есть только 3 варианта:

  1. Не делайте этого. Вручную разбивать свою страницу на кучу микроприложений или островов. (Astro)
  2. Делайте все передачи данных с помощью инъекции зависимостей. Каждая часть вашей страницы независима и передается по мере необходимости. (Qwik)
  3. Иметь компилятор, достаточно умный, чтобы понять состояние вашего приложения и выводить оптимизированные пакеты. (Marko)

Все они требуют особого внимания. Первый требует, чтобы вы определили острова и только масштабировали. Второй заставляет вас выводить состояние за пределы ваших компонентов, что оказывает большое давление на Developer Experience (удобство разработки), например, можете ли вы передавать props.children? Есть ли ограничения на то, что может быть сериализовано? Третий вариант чрезвычайно сложен и требует специализированного языка и годы исследований и разработок.

Но результаты очевидны. Вот простой пример влияния, которое команда Marko увидела, когда отключила эту оптимизацию на некоторых страницах eBay.

Оптимизация позволяет сократить размер пакета JavaScript на 60%-84%!

Почему так много? Marko не является огромной библиотекой весом 13 кб в минимизированном и gzipped виде. Очевидно, что вы экономите на коде компонентов, но это еще не все. Наличие компонентов только на сервере также означает, что некоторые обёртки API и форматеры, такие как Moment и Lodash, просто никогда не должны попадать в браузер.

Marko no-bundle streaming также помогает в этом случае, поскольку он может обслуживать страницу немедленно, не дожидаясь асинхронных вызовов. Он может передавать контент в серверные рендеринговые объекты в реальном времени, не втягивая код в связку.

К делу

Если вам нужна резкая производительность для начальной загрузки, как в электронной коммерции, где миллисекунды означают потенциальную потерю продаж; где вам не гарантирована сеть или мощность устройств ваших клиентов; вам не подходит такой фреймворк, как Next.js. Он просто не оптимизирован для этого. Даже если вы используете его с меньшей библиотекой, такой как Preact, вы все равно делаете слишком много в браузере.

Вы можете подумать, а как же вещи, которые появятся в React 18, такие как серверные компоненты и потоковый SSR? Они могут помочь, но они не изменят физику.

Потоковый SSR невероятно мощный, как уже было замечено в Marko и Solid, так как он устраняет начальную задержку на асинхронных данных. Таким образом можно устранить большую часть накладных расходов, связанных с серверным рендерингом по требованию по сравнению со статической генерацией сайта, но это само по себе не уменьшает количество отправляемого JavaScript.

Серверные компоненты значительно облегчают написание специализированных API. Это экономит отправку кода (Lodash и Moment не попадут в браузер), но вы все еще выполняете проверку на различия (diffs) на стороне клиента, шаблон отправляется через API. Вы можете рассматривать это как ленивую загрузку/гидратацию, но на самом деле это увеличивает размер основной библиотеки для ее обработки. Если подумать об этом с другой стороны, то, учитывая правила Server Component, это просто статические части, которые MPA все равно никогда не будет отправлять в браузер!

Заключение

Правильный инструмент для работы. Да-да-да. Если говорить серьезно, то, хотя я мечтаю о будущем, когда все это будет одним и тем же, сегодня MPA-фреймворки могут оптимизировать таким образом, который просто недоступен для тех, кто строит с учетом архитектуры SPA.

Для этого не нужен другой язык или платформа. Я не говорю, что нужно вытаскивать Rails или Django. Вы все еще можете получить современное исполнение JavaScript в одном приложении и почувствовать его уже с помощью имеющихся инструментов. Но если вы заботитесь о максимальной производительности при начальной загрузке страницы, вы не найдете этого в вероятных кандидатах.

В следующий раз, когда вы встретите новое решение для электронной коммерции, которое рекламирует свою скорость. Спросите, оптимизировано ли оно для MPA, потому что если нет, то это больше похоже на то же самое, к чему мы уже все привыкли. Не зря eBay, Alibaba и Builder инвестировали в создание собственных JavaScript-фреймворков.

В этом нет ничего нового, кроме пересмотра основ. Но прошло уже десятилетие, так что, возможно, пришло время. Не поймите меня неправильно. Я являюсь автором одного из таких SPA-фреймворков, который гордится тем, что является самым быстрым из всех на клиенте и сервере. Но архитектура превосходит скорость почти всегда, когда речь идет о предоставлении наилучшего пользовательского опыта. Так что в зависимости от вашего сценария использования, может быть, вам не нужен этот SPA?

Источник: https://dev.to/this-is-learning/building-javascript-frameworks-to-conquer-ecommerce-3glc

Дополнительно почитать: https://habr.com/ru/post/564990/