Jamstack: философия веб-разработки на примере Next.js

Сперва JAMstack считался лишь комбинацией JavaScript, API и MarkUp. Теперь веб-разработка Jamstack превратилась в настоящую философию.

5301

На этапе планирования сайта Академии IBS Dunice мы обратили внимание на недавно появившийся в мировом IT-сообществе принципиально иной способ создания сайтов под названием Jamstack.

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

На заре своего становления JAMstack считался лишь комбинацией JavaScript, API и MarkUp. Но сегодня это не так. Netlify, компания-создатель Jamstack, отказалась от сухой аббревиатуры JAM и сделала из Jamstack настоящую философию веб-разработки.

Jamstack: философия веб-разработки на примере Next.js 1

Что такое Jamstack

Jamstack сегодня можно определить как современную архитектуру веб-разработки, которая позволяет создавать веб-сайты на основе методологии микросервисов. Она даёт все преимущества статических страниц: высокую производительность и трафикоустойчивость, высокую скорость загрузки, безопасность, отличные показатели SEO и т. д.

Лучше понять, что такое Jamstack, можно на примере её отличий в рабочем процессе. На графике очень упрощённо, но тем не менее наглядно изображено, что происходит под капотом.

Jamstack: философия веб-разработки на примере Next.js 2

Сегодня существует два традиционных подхода: MPA и SPA. При этом Jamstack содержит все плюсы MPA и SPA и не содержит ни одного из их минусов. На изображении ниже плюсы отмечены зелёным, минусы — красным.

Jamstack: философия веб-разработки на примере Next.js 3

Почему Jamstack

Архитектура Jamstack имеет множество преимуществ вне зависимости от того, создаёте ли вы масштабный продукт электронной коммерции, SaaS-приложение или, как мы, корпоративный сайт. Ниже мы собрали лишь некоторые из её ключевых достоинств.

Высокая производительность

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

А когда речь идёт об улучшении показателя TTFB (Time to First Byte), нет ничего лучше, чем предварительно созданные файлы, передаваемые через CDN.

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

Повышенная безопасность

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

Например, при использовании mysql/mongodb, apache/nginx, RoR/Node/PHP, …, уязвимости могут быть в любом из этих звеньев.

Простое и дешёвое масштабирование

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

FAQ / Возможные проблемы (спойлер: проблемы, чаще всего, надуманные)

1. Если есть предварительный рендеринг, то как быть с обновлениями?

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

Не стоит забывать, что всё ещё можно использовать JavaScript на фронте. Также существуют DPR/ISR/DSR.

2. Jamstack предполагает git-ориентированный рабочий процесс. Но я не хочу, чтобы пользователи имели доступ к репозиторию. Ни в каком виде. Лучше я воспользуюсь WordPress.

Можно где-то разместить свой отдельный сервер WordPress (или любую другую Headless-совместимую CMS), а у этих CMS есть JSON API. Этот API можно использовать или на этапе полной (или частичной) сборки, или же во время runtime (посредством вызовов API).

Почему Next.js

Самым популярным Jamstack-фреймворком, по данным jamstack.org, является Next.js. В общем рейтинге всех фреймворков он также занимает высокое место:

Jamstack: философия веб-разработки на примере Next.js 4
Jamstack: философия веб-разработки на примере Next.js 5

Но ещё пару лет назад поверить в эту статистику было бы сложно, ведь когда Next.js только появился на сцене, он был не очень совместим с архитектурой Jamstack, а именно — с предпочтительным в её философии методом статической генерации сайта (SSG).

Дело в том, что одним из основных принципов работы Next.js является рендеринг на стороне сервера (SSR), и эти два подхода к созданию приложений — SSG и SSR, казалось бы, противоположны, и их невозможно объединить.

Но в 2020 году в версии Next.js 9.3 появилась улучшенная поддержка SSG, а в 2021-м появилась поддержка гибридной модели, при которой можно пользоваться одновременно и в равной степени свободно как SSG, так и SSR. Поэтому Next.js теперь не такой уж и плохой выбор для архитектуры Jamstack, а даже наоборот — очень популярный.

Несмотря на огромное многообразие выбора платформ для создания своего сайта или приложения на архитектуре Jamstack, мы считаем Next.js поистине уникальным фреймворком. Почему?

1. Он одновременно поддерживает:

  • (Server/SSR) рендеринг на стороне сервера во время выполнения (по аналогии с MPA);
  • (Static) автоматический рендеринг в виде статического HTML;
  • (SSG) автоматическую генерацию в виде статического HTML + JSON;
  • (ISR) инкрементную статическую регенерацию.

2. Из коробки в Next.js есть:

  • CI/CD с live previews;
  • долгожданный и революционный встроенный компонент Image;
  • роутинг страниц (с фоновой предзагрузкой содержимого внутренних ссылок — в формате JSON «под капотом»);
  • serverless;
  • автообновляемые SSL-сертификаты (https);
  • i18n;
  • http/2;
  • CDN-кэширование и ревалидация;
  • s(css)-модули.

3. Сравнивая Next.js с его основным конкурентом Nuxt.js, следует отметить, что:

  • согласно npmtrends.com, популярность Next.js растет значительно быстрее;
  • у Next.js более чем в 2 раза больше звезд на Github;
  • с Next.js можно использовать Vercel, который подходит для него лучше, чем универсальные платформы для статических генераторов.

Метрики качества веб-сайта на примере работы с Next.js

В этой части мы расскажем, как можно улучшить показатели веб-сайта на примере опыта работы над сайтом Академии IBS Dunice edu.dunice.net. Сайт разрабатывался на Next.js и Vercel, поэтому преимущества данного стека можно будет наблюдать на практике.

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

  • Performance
  • SEO
  • Accessibility
  • Best practices
  • PWA

Фактически здесь они расположены по убыванию приоритета. Далее речь пойдёт о метрике Performance, потому как она самая важная, а также потому, что остальные метрики технически оптимизируются проще и однозначнее.

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

Так, Google недавно включил скорость загрузки сайта в число наиболее важных из ключевых метрик, а по некоторым данным, более 50% мобильных пользователей покидают веб-сайты, если их загрузка длится дольше трёх секунд.

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

Метрика Performance состоит:

  • из основных метрик (по версии/инициативе Google)

LCP (Largest Contentful Paint)
FID (First Input Delay)
CLS (Cumulative Layout Shift)

  • дополнительных метрик

TTFB (Time To First Byte)
FP (First Paint)
FCP (First Contentful Paint)
TBT (Total Blocking Time)
TTI (Time to Interactive)

  • других метрик (не на все из них можно как-то повлиять)

RTT (Round Trip Time)
SSR on/off (Server Side Rendering) — опциональный этап, зависит от выбираемой архитектуры
F-CR (Fetching / Computing & Rendering) — аббревиатура, созданная исключительно в рамках данного текста

Зависимость метрик имеет следующий вид:

SSR → RTT → TTFB → F-CR {FP → FCP → LCP → остаточный TBT → FID (~=TTI)}

Измеряют метрики с помощью таких инструментов, как Chrome Dev Tool, web.dev/measure, ​​Web Vitals. PageSpeed Insights непосредственно измеряет метрику Performance. Есть ещё Webpack bundle analyzer: для Next.js — @next/bundle-analyzer.

Высокие результаты метрик сайта edu.dunice.net на web.dev/measure видны на этом скриншоте:

Jamstack: философия веб-разработки на примере Next.js 6

Далее мы дадим практические советы по улучшению показателей Performance, как раз основываясь на опыте работы над сайтом edu.dunice.net.

Пометка NextVercel в последующих пунктах будет означать, что то или иное действие в связке Next и Vercel выполняется автоматически.

TTFB (Time To First Byte)

  • Сократить RTT за счёт распределённого хостинга, чтобы ответы на запросы браузера приходили от ближайшего сервера (NextVercel: CDN).
  • Исключить (или закэшировать результаты) SSR для целевых страниц (NextVercel: Static & SSG pages and Edge Functions).

Fetching (download time only)

  • Исключить или сократить переадресации (redirects).
  • Минифицировать JS и CSS (NextVercel: out of the box by Webpack).
  • Включить gzip и http/2 на стороне контент-сервера (NextVercel: CDN).
  • Оптимизировать разрешение, качество и формат (webp или avif)* всех изображений. Это даёт максимальный прирост. Также стоит задать приоритет изображениям, отображаемым при загрузке (NextVercel: component + есть встроенная поддержка Low Quality Image Placeholders (LQIP)).*Нужно учитывать, что не все браузеры поддерживают данные форматы, и генерировать и доставлять нужные форматы для всех изображений автоматически — это сложная задача. Next.js всё это поддерживает с 11-й версии.

F-CR (Fetching + Computing & Rendering)

  • Исключить или сократить Client Side Rendering (CSR) по крайней мере той части контента, которая соответствует LCP (NextVercel: render at build time ~ Jamstack).
  • Отложить загрузку и вычисление* частей контента (в том числе и «тяжёлых» библиотек-зависимостей), которые не требуются для LCP. Для этого необходимо использовать Code Splitting (разделение кода) и Lazy loading (ленивую загрузку) (NextVercel: Dynamic Import).
    Здесь можно найти пример кода.
    * Имеется в виду, что движок V8 затрачивает время на выполнение JS и это время влияет на все метрики после TTFB.Также очень сильно влияет, по крайней мере на синтетические метрики, загрузка аналитик типа Google Analytics и Yandex Webmaster, поэтому рекомендуется отложить их загрузку* до наступления одного (того, что наступит раньше — race) из условий:
    1) прошло несколько секунд (время заведомо большее, чем LCP/TTI);
    2) пользователь совершил какое-либо действие (нажал любую кнопку, сдвинул курсор мыши, изменил ориентацию landscape/tablet).Пример кода здесь.
    *— Если сделать это правильно, то аналитики будут работать корректно, а боты поисковиков, которые отслеживают скорость загрузки страниц, не будут вызывать никаких событий пользовательского ввода (при том прирост скорости загрузки будет не только синтетическим, но и фактическим — для реального пользователя).— Не рекомендуется делать подмену контента на основании заголовка запроса User Agent на сервере с целью отдачи поисковикам содержимого страниц без подключенных аналитик. Также можно использовать (s)css modules, что, кроме прочего, сократит размер загружаемых стилей (как минимум до момента LCP).Если все стили будут в одном файле, это повлияет на время начала интерпретации стилей контента, видимого при загрузке (scroll position 0). (NextVercel: out of the box). Critical (render-blocking) css можно выделить отдельно и загружать раньше остальных стилей, включив содержимое этих стилей непосредственно внутрь тега