Эта статья — перевод оригинальной статьи "Introducing Next.js Commerce 2.0".

Также я веду телеграм канал “Frontend по-флотски”, где рассказываю про интересные вещи из мира разработки интерфейсов.

Вступление

Сегодня мы с радостью представляем Next.js Commerce 2.0.

  • App Router Ready: Использование компонентов React Server, Server Actions, встроенных лейаутов, метаданных и всех новых шаблонов из недавно выпущенного App Router.

  • Динамическая витрина: Динамическая витрина с Edge-рендерингом, работающая со скоростью статической. Настраивайте контент без ущерба для производительности.

  • Упрощенная архитектура: Next.js Commerce теперь представляет собой один провайдер на репозиторий, что позволяет сократить объем кода и уменьшить количество абстракций для вашего приложения.

Наш новый шаблон-акселератор интернет-магазина демонстрирует лучшие шаблоны для создания составных коммерческих приложений, включая поддержку BigCommerce, Medusa, Saleor, Shopify и Swell.

Ознакомьтесь с демонстрационной версией или разверните свою собственную версию уже сегодня.

Почему сложно создать сайт интернет-магазина?

Когда Google объявил о том, что удобство работы со страницей станет одним из факторов ранжирования в результатах поиска, а Amazon обнаружила, что всего 100 миллисекунд дополнительного времени загрузки стоят ей 1% продаж, это заставило сайты электронной коммерции поднять планку или пострадать от последствий.

Однако, по данным Web Almanac, сайты интернет-магазинов по-прежнему испытывают трудности с достижением высоких показателей.

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

  • Они делают много запросов на странице. У 50-го процентиля всех сайтов электронной коммерции на главной странице в мобильном режиме был 101 запрос. Кажется, что это много, но подумайте обо всей информации о товарах и продажах, которая появляется на большинстве домашних страниц.

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

  • Основное внимание в них уделяется персонализации. Это включает рекомендации товаров на основе истории покупок, привычек или местоположения, товаров в корзине, информации о пользователе и т.д.

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

Например, темы магазинов Shopify требуют только минимального среднего показателя производительности Lighthouse в 60 баллов для товаров, коллекций и главной страницы темы, как для настольных, так и для мобильных устройств.

Крупные розничные компании, такие как Under Armour, Walmart, Target, Nike и другие, доверяют свою электронную коммерцию Next.js, которая помогает им добиваться лучших результатов. Давайте посмотрим, как это делается.

Next.js Commerce v1

Первая версия Next.js Commerce была анонсирована на конференции Next.js Conf 2020 и одновременно с Next.js 10. Новые функции Next.js того времени, такие как next/image с автоматической оптимизацией изображений и статическим и динамическим рендерингом на основе каждой страницы, обеспечили ингредиенты для создания лучшего опыта электронной коммерции.

В сочетании с переходом от монолитов к безголовой электронной коммерции мы смогли поднять планку для сайтов электронной коммерции. Next.js Commerce воплотил в себе лучшие в своем классе, высокопроизводительные и оптимизированные коммерческие возможности, включая превосходные показатели веб-ядра, SEO-оптимизацию, инкрементную регенерацию статики, предварительную выборку ссылок и многое другое.

Эта версия Next.js Commerce стала огромным шагом вперед, но для высокодинамичных сайтов электронной коммерции все еще оставались возможности для совершенствования.

Next.js Commerce 2.0 - динамические витрины со скоростью статических

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

Даже с развитием технологий Server-Side Rendering (SSR), Static Site Generation (SSG) и Incremental Static Regeneration (ISR) создание сайта электронной коммерции по-прежнему остается сложной задачей.

Для достижения наибольшей эффективности нам необходимо нечто более детальное для управления статической и динамической частями нашего приложения. Именно здесь Next.js 13 и появление App Router открывают доступ к более глубокому уровню управления, позволяя создавать витрины магазинов, которые кажутся статичными, но при этом являются полностью динамичными.

Результаты производительности

Благодаря использованию новейших возможностей Next.js 13 и облака Vercel Frontend Cloud, Next.js Commerce 2.0 достигает невероятной производительности, демонстрируя динамику со скоростью статики.

Когда мы представили предварительную версию, некоторые отметили, что производительность сайта кажется статичной. Пришлось пояснить, что это динамическая, рендерируемая сервером витрина, работающая на уровне статически кэшируемой страницы. Это стало возможным благодаря новой архитектуре кэширования в Next.js App Router и Vercel Data Cache.

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

Давайте рассмотрим некоторые возможности Next.js 13, благодаря которым это стало возможным.

Лейауты и страницы

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

React Server Components, Streaming, и Suspense

React Server Components (RSC) позволяют нам выполнять как можно больше работы на сервере, включая динамические вызовы API, прежде чем вернуть полностью отрисованный пользовательский интерфейс. Это означает меньший размер пакета JavaScript на стороне клиента и меньшее количество запросов на стороне клиента. Это также означает отсутствие смещения макета, отсутствие загрузочных спиннеров и более быстрое время интерактивного взаимодействия.

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

  • Лейаут, страница, заголовок и фильтры поисковой сортировки рендерятся на сервере, они доступны при первой загрузке страницы.

  • Корзина, категории поиска, товары и футер, использующие Suspense, загружаются независимо друг от друга при готовности каждого элемента.

Получение и кэширование данных

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

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

Мы используем Shopify Storefront API, который использует GraphQL. GraphQL ожидает, что все запросы будут POST-запросами. Мы имитируем встроенную в Next.js функциональность кэширования всех вызовов по умолчанию, за исключением мутаций.

const domain = `https://${process.env.SHOPIFY_STORE_DOMAIN}`;
const endpoint = `${domain}${SHOPIFY_GRAPHQL_API_ENDPOINT}`;
const key = process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN;

export async function shopifyFetch({
  cache = 'force-cache',
  headers,
  query,
  tags,
  variables
}) {
  const result = await fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Shopify-Storefront-Access-Token': key,
      ...headers
    },
    body: JSON.stringify({
      ...(query && { query }),
      ...(variables && { variables })
    }),
    cache,
    ...(tags && { next: { tags } })
  });

  const body = await result.json();

  if (body.errors) {
    throw body.errors[0];
  }

  return {
    status: result.status,
    body
  };
}

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

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

import { getProductQuery } from './queries/product';

const res = await shopifyFetch({
  query: getProductQuery,
  tags: ['products'],
  variables: {
    handle: 'acme-t-shirt'
  }
});

Теперь мы можем подписаться на вебхуки Shopify, чтобы получать уведомления об изменении данных о товаре, и перепроверять данные о товаре с помощью revalidateTag.

import { revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export const runtime = 'edge';

export async function POST(req) {
  const productWebhooks = ['products/create', 'products/delete', 'products/update'];
  const topic = headers().get('x-shopify-topic') || 'unknown';
  const isProductUpdate = productWebhooks.includes(topic);

  if (!isProductUpdate) {
    // We don't need to revalidate anything for any other topics.
    return NextResponse.json({ status: 200 });
  }

  if (isProductUpdate) {
    revalidateTag('products');
  }

  return NextResponse.json({ status: 200, revalidated: true, now: Date.now() });
}

Edge Runtime

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

С помощью Edge Runtime вы можете выполнять код рядом с посетителями, делая быстрый веб доступным для всех, независимо от их местоположения. Всего одна строка кода, добавленная на страницу или в API-маршрут, позволяет Next.js Commerce обеспечить высочайший уровень производительности.

import { Carousel } from 'components/carousel';
import { ThreeItemGrid } from 'components/grid/three-items';
import Footer from 'components/layout/footer';
import { Suspense } from 'react';

export const runtime = 'edge';

export const metadata = {
  description: 'High-performance ecommerce store built with Next.js, Vercel, and Shopify.',
  openGraph: {
    type: 'website'
  }
};

export default async function HomePage() {
  return (
    <>
      <ThreeItemGrid />
      <Suspense>
        <Carousel />
        <Suspense>
          <Footer />
        </Suspense>
      </Suspense>
    </>
  );
}

Server Actions

С помощью Server Actions (alpha) мы можем располагать мутации данных на стороне сервера вместе с вызывающим их пользовательским интерфейсом, что избавляет от необходимости создавать маршруты API, используемые только вашим приложением, и сокращает количество JavaScript на стороне клиента, уменьшая размер бандла.

'use client';

import { addItem } from 'components/cart/actions';
import { useRouter } from 'next/navigation';
import { useTransition } from 'react';

export function AddToCart({selectedVariantId}) {
  const router = useRouter();
  const [isPending, startTransition] = useTransition();

  return (
    <button
      aria-label="Add item to cart"
      disabled={isPending}
      onClick={() => {
        startTransition(async () => {
          const error = await addItem(selectedVariantId);

          if (error) {
            alert(error);
            return;
          }

          router.refresh();
        });
      }}
    >
      Add To Cart
    </button>
  );
}
'use server';

import { addToCart, createCart, getCart } from 'lib/shopify';
import { cookies } from 'next/headers';

export const addItem = async (variantId) => {
  let cartId = cookies().get('cartId')?.value;
  let cart;

  if (cartId) {
    cart = await getCart(cartId);
  }

  if (!cartId || !cart) {
    cart = await createCart();
    cartId = cart.id;
    cookies().set('cartId', cartId);
  }

  if (!variantId) {
    return new Error('Missing variantId');
  }
  try {
    await addToCart(cartId, [{ merchandiseId: variantId, quantity: 1 }]);
  } catch (e) {
    return new Error('Error adding item', { cause: e });
  }
};

Стратегия работы с репозиториями

Предыдущая архитектура Next.js Commerce v1 представляла собой мультивендорное, взаимодействующее решение, включающее интеграцию с десятью поставщиками услуг электронной коммерции. В версии 2 мы удалили около 145 000 строк кода, сделав проект более простым, удобным для сопровождения и понятным, а также рассказав о новейших возможностях Next.js 13.

Партнеры могут создавать форки для репозитория Next.js Commerce и добавлять в него поддержку своей платформы. Мы рады, что наши партнеры BigCommerce, Medusa, Saleor и Swell приняли эту новую концепцию и уже имеют готовые шаблоны и демо-версии, использующие Next.js Commerce 2.0. Если вы хотите добавить поддержку своей платформы, следуйте инструкциям и откройте запрос на внесение изменений, чтобы добавить свою платформу в список.

Чтобы начать работу с собственным магазином электронной коммерции, вы можете развернуть свою собственную версию Next.js Commerce 2.0 + Shopify, посетив страницу шаблона и воспользовавшись нашей кнопкой "развернуть одним щелчком".

Комментарии (0)