Meet Next.js Commerce 2.0

This article is a translation of the original article “Introducing Next.js Commerce 2.0“.

I also run a telegram channelFrontend in a navy way”, where I talk about interesting things from the world of interface development.

Introduction

Today we are proud to present Next.js Commerce 2.0.

  • App Router Ready: Using React Server components, Server Actions, built-in layouts, metadata and all new templates from the recently released App Router.

  • Dynamic showcase: Dynamic showcase with edge rendering, running at static speed. Customize content without sacrificing performance.

  • Simplified architecture: Next.js Commerce is now a single provider per repository, reducing the amount of code and abstraction for your application.

Our new online store accelerator template showcases the best templates for building composite commercial applications, including support for BigCommerce, Medusa, Saleor, Shopify, and Swell.

Check out the demo or deploy your own version already today.

Why is it difficult to create an online store website?

When Google announced that usability of the page will become one of the ranking factors in search results, and Amazon found that only 100 milliseconds of extra load time cost her 1% of sales.this has caused e-commerce sites to raise the bar or suffer the consequences.

However, according to Web Almanac, e-commerce sites still struggle to achieve high performance.

Online shopping sites are more complicated than it seems at first glance. What is it about e-commerce that contributes to obtaining such indicators?

  • They make a lot of requests per page. The 50th percentile of all e-commerce sites had 101 searches on their mobile homepage. Sounds like a lot, but think about all the product and sales information that appears on most homepages.

  • They have a lot of weight. Videos and images are the first and second most requested resource types, as well as the first and second largest contributors to page weight. Remember how many images of products and sales you see only on the main page.

  • The focus is on personalization. This includes product recommendations based on purchase history, habits or location, items in the cart, user information, and more.

Many trading platforms come with pre-built templates to help you get started quickly, but they often don’t have the rigor needed to scale and deliver a high level of performance.

For example, Shopify store themes only require minimum average Lighthouse performance score of 60 points for products, collections and theme home page, both desktop and mobile.

Major retailers like Under Armor, Walmart, Target, Nike, and more trust their Next.js e-commerce to help them achieve better results. Let’s see how it’s done.

Next.js Commerce v1

First version Next.js Commerce was announced at the conference Next.js Conf 2020 and at the same time Next.js 10. New Next.js features of the time, such as next/image with automatic image optimization and static and dynamic rendering on a per-page basis, provided the ingredients to create the best e-commerce experience.

Combined with the move from monoliths to headless e-commerce, we have been able to raise the bar for e-commerce sites. Next.js Commerce delivers best-in-class, high-performance, and optimized commerce features, including superior web core performance, SEO optimization, incremental static regeneration, link prefetching, and more.

This version of Next.js Commerce was a huge step forward, but there was still room for improvement for highly dynamic e-commerce sites.

Next.js Commerce 2.0 – dynamic storefronts at the speed of static

There are many dynamic elements in commerce, such as a user’s shopping cart, search results, items purchased and availability, product recommendations, and so on.

Even with the evolution of Server-Side Rendering (SSR), Static Site Generation (SSG) and Incremental Static Regeneration (ISR) technologies, building an e-commerce site is still a challenging task.

To be most efficient, we need something more granular to manage the static and dynamic parts of our application. This is where Next.js 13 and the advent of App Router opens up a deeper level of control, allowing you to create storefronts that appear static yet are fully dynamic.

Performance Results

Using the latest features Next.js 13 and Vercel Frontend Cloud, Next.js Commerce 2.0 Achieves Incredible Performancedemonstrating dynamics at the speed of statics.

When we released the preview, some people commented that the site’s performance seemed static. I had to clarify that this is a dynamic, server-rendered storefront that works at the level of a statically cached page. This was made possible thanks to new caching architecture in Next.js App Router and Vercel Data Cache.

In addition to the new release, we also made a small redesign to give the theme a fresh, modern look.

Let’s take a look at some of the Next.js 13 features that make this possible.

Layouts and pages

App Router introduces a new filename routing convention that includes layouts and pages. This allows you to create and share layouts and site-wide components such as headers and footers, and for e-commerce, create a shopping cart that is accessible from anywhere on the site. The overall impression of working with the site becomes much faster. It was possible before, but now it’s even easier.

React Server Components, Streaming, and Suspense

React Server Components (RSC) allow us to do as much work as possible on the server, including dynamic API calls, before returning a fully rendered UI. This means smaller client-side JavaScript batch size and fewer client-side requests. It also means no layout shift, no loading spinners, and faster interactive times.

In combination with streaming and suspension we can prioritize and return parts of the UI as they are ready rather than waiting for the entire page to be ready. Thus, users get content faster. Your site will no longer be as slow as the slowest backend. Portions of the site below the screen edge can be rendered later, while users see more live content above the screen edge.

  • The layout, page, title, and search sorting filters are server-rendered and available when the page is first loaded.

  • The cart, search categories, products, and footer using Suspense load independently when each item is ready.

Retrieving and caching data

The biggest mental model shift in Next.js 13 is to stop thinking about what pages should be static or dynamic and start thinking about what data is static or dynamic. Moving the decisions about static and dynamic to the realm of data acquisition gives you more control over when and where to serve static or dynamic content.

Using new paradigms receiving And caching data, revalidation (also known as incremental static regeneration) is also moved to the individual sample.

We use Shopify Storefront API, which uses GraphQL. GraphQL expects all requests to be POST requests. We’re mimicking Next.js’s built-in caching functionality for all calls by default, with the exception of mutations.

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
  };
}

Since all data is cached by default, we need a way to trigger data revalidation when needed. Let’s take products as an example.

When we update the product description, inventory, etc. in Shopify, we want the site to reflect those changes. We also don’t want the site to make extra calls to get this data if it doesn’t change. So we can use the default caching but add a revalidation tag.

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

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

Now we can subscribe to Shopify webhooksto receive notifications about product data changes, and recheck product data using 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

As a rule, shop windows are located in the same region. This does not allow you to quickly serve customers, no matter where they are. Large retail companies have the ability to use a large amount of computing resources around the world, but this can be expensive and difficult to maintain. Vercel makes it easy and cost-effective to create a global store. Expanding to new regions occurs in seconds without the need for manual infrastructure creation.

By using Edge Runtime you can code alongside your visitors, making the fast web accessible to everyone, no matter where they are. With just one line of code, added to a page or API route, Next.js Commerce delivers the highest level of performance.

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

By using Server Actions (alpha) we can host data mutations on the server side along with the UI that calls them, which eliminates the need to create API routes that are used only by your application and reduces the amount of JavaScript on the client side, reducing the size of the bundle.

'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 });
  }
};

Repository Strategy

Previous Next.js Commerce Architecture v1 was a multi-vendor, interoperable solution that included integration with ten e-commerce service providers. In version 2, we removed about 145,000 lines of code, making the project simpler, more maintainable, and easier to understand, as well as highlighting the latest Next.js 13 features.

Partners can fork the Next.js Commerce repository and add support for their platform to it. We are glad that our partners BigCommerce, medusa, Saleor And Swell adopted this new concept and already have ready-made templates and demos, using Next.js Commerce 2.0. If you want to add support for your platform follow instructions and open a pull request to add your platform to the list.

To get started with your own eCommerce store, you can deploy your own Next.js Commerce 2.0 + Shopify. by visiting the template page and using our “expand with one click” button.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *