ce-nextjs-patterns

📁 commercengine/skills 📅 5 days ago
4
总安装量
4
周安装量
#48965
全站排名
安装命令
npx skills add https://github.com/commercengine/skills --skill ce-nextjs-patterns

Agent 安装分布

opencode 4
gemini-cli 4
claude-code 4
github-copilot 4
codex 4
kimi-cli 4

Skill 文档

Next.js Patterns

For basic setup, see setup/.

Impact Levels

  • CRITICAL – Breaking bugs, security holes
  • HIGH – Common mistakes
  • MEDIUM – Optimization

References

Reference Impact
references/server-vs-client.md CRITICAL – storefront(cookies()) vs storefront()
references/token-management.md HIGH – Cookie-based token flow in Next.js

Mental Model

The storefront() function adapts to the execution context:

Context Usage Token Storage
Client Components storefront() Browser cookies
Server Components storefront(cookies()) Request cookies
Server Actions storefront(cookies()) Request cookies (read + write)
Root Layout storefront({ isRootLayout: true }) Memory fallback
Build time (SSG) storefront() Memory (no user context)

Setup

1. Install

npm install @commercengine/storefront-sdk-nextjs

2. Create Config

// lib/storefront.ts
export { storefront } from "@commercengine/storefront-sdk-nextjs";

3. Root Layout

// app/layout.tsx
import { StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
import { storefront } from "@/lib/storefront";

// Root Layout requires explicit flag — no request context available
const sdk = storefront({ isRootLayout: true });

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <StorefrontSDKInitializer />
        <h1>Welcome to My Brand Store</h1>
        {children}
      </body>
    </html>
  );
}

4. Environment Variables

# .env.local
NEXT_PUBLIC_STORE_ID=your-store-id
NEXT_PUBLIC_API_KEY=your-api-key
NEXT_BUILD_CACHE_TOKENS=true  # Faster builds with token caching

Key Patterns

Server Component (Data Fetching)

// app/products/page.tsx
import { storefront } from "@/lib/storefront";
import { cookies } from "next/headers";

export default async function ProductsPage() {
  const sdk = storefront(cookies());
  const { data, error } = await sdk.catalog.listProducts({
    page: 1, limit: 20,
  });

  if (error) return <p>Error: {error.message}</p>;

  return (
    <div>
      {data.products.map((product) => (
        <div key={product.id}>{product.name}</div>
      ))}
    </div>
  );
}

Server Actions (Mutations)

// app/actions.ts
"use server";

import { storefront } from "@/lib/storefront";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";

export async function loginWithEmail(email: string) {
  const sdk = storefront(cookies());

  const { data, error } = await sdk.auth.loginWithEmail({
    email,
    register_if_not_exists: true,
  });

  if (error) return { error: error.message };
  return { otp_token: data.otp_token, otp_action: data.otp_action };
}

export async function verifyOtp(otp: string, otpToken: string, otpAction: string) {
  const sdk = storefront(cookies());

  const { data, error } = await sdk.auth.verifyOtp({
    otp,
    otp_token: otpToken,
    otp_action: otpAction,
  });

  if (error) return { error: error.message };
  redirect("/account");
}

export async function addToCart(cartId: string, productId: string, variantId: string | null) {
  const sdk = storefront(cookies());

  const { data, error } = await sdk.cart.addDeleteCartItem(
    { id: cartId },
    { product_id: productId, variant_id: variantId, quantity: 1 }
  );

  if (error) return { error: error.message };
  return { cart: data.cart };
}

Static Site Generation (SSG)

// app/products/[slug]/page.tsx
import { storefront } from "@/lib/storefront";

// Pre-render product pages at build time
export async function generateStaticParams() {
  const sdk = storefront(); // No cookies at build time
  const { data } = await sdk.catalog.listProducts({ limit: 100 });

  return (data?.products ?? []).map((product) => ({
    slug: product.slug,
  }));
}

export default async function ProductPage({ params }: { params: { slug: string } }) {
  const sdk = storefront(); // No cookies for static pages
  const { data, error } = await sdk.catalog.getProductDetail({
    product_id_or_slug: params.slug,
  });

  if (error) return <p>Product not found</p>;
  const product = data.product;

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.selling_price}</p>
      {/* AddToCartButton is a Client Component */}
    </div>
  );
}

Client Component

"use client";

import { storefront } from "@/lib/storefront";

export function AddToCartButton({ productId, variantId }: Props) {
  async function handleClick() {
    const sdk = storefront(); // No cookies in client components
    const { data, error } = await sdk.cart.addDeleteCartItem(
      { id: cartId },
      { product_id: productId, variant_id: variantId, quantity: 1 }
    );
  }

  return <button onClick={handleClick}>Add to Cart</button>;
}

Common Pitfalls

Level Issue Solution
CRITICAL Missing cookies() in Server Components Use storefront(cookies()) for user-specific data on the server
CRITICAL Auth in Server Components instead of Actions Auth endpoints that return tokens MUST be in Server Actions, not Server Components
HIGH Missing StorefrontSDKInitializer Required in root layout for automatic anonymous auth and session continuity
HIGH Using cookies() in Client Components Client Components use storefront() (no cookies) — tokens managed via browser cookies
MEDIUM Slow builds Set NEXT_BUILD_CACHE_TOKENS=true for token caching during SSG
MEDIUM Root Layout missing isRootLayout flag Root Layout runs outside request context — use storefront({ isRootLayout: true })

See Also

  • setup/ – Basic SDK installation
  • auth/ – Authentication flows
  • cart-checkout/ – Cart management

Documentation