Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Commerce #38

Merged
merged 8 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ jobs:
node-version: lts/*
- name: Install dependencies
run: npm install -g pnpm && pnpm install
- name: build all workers
run: pnpm -r build:worker
- name: Install Playwright browsers
run: pnpm run install-playwright
- name: Run playwright tests
Expand Down
7 changes: 7 additions & 0 deletions examples/vercel-commerce/.dev.vars.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
COMPANY_NAME="Vercel Inc."
TWITTER_CREATOR="@vercel"
TWITTER_SITE="https://nextjs.org/commerce"
SITE_NAME="Next.js Commerce"
SHOPIFY_REVALIDATION_SECRET=""
SHOPIFY_STOREFRONT_ACCESS_TOKEN=""
SHOPIFY_STORE_DOMAIN="[your-shopify-store-subdomain].myshopify.com"
7 changes: 7 additions & 0 deletions examples/vercel-commerce/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
COMPANY_NAME="Vercel Inc."
TWITTER_CREATOR="@vercel"
TWITTER_SITE="https://nextjs.org/commerce"
SITE_NAME="Next.js Commerce"
SHOPIFY_REVALIDATION_SECRET=""
SHOPIFY_STOREFRONT_ACCESS_TOKEN=""
SHOPIFY_STORE_DOMAIN="[your-shopify-store-subdomain].myshopify.com"
43 changes: 43 additions & 0 deletions examples/vercel-commerce/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage
.playwright

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env*
!.env.example

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

# cf
.dev.vars
.wrangler
.worker-next
28 changes: 28 additions & 0 deletions examples/vercel-commerce/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Next.js: debug server-side",
"type": "node-terminal",
"request": "launch",
"command": "pnpm dev"
},
{
"name": "Next.js: debug client-side",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000"
},
{
"name": "Next.js: debug full stack",
"type": "node-terminal",
"request": "launch",
"command": "pnpm dev",
"serverReadyAction": {
"pattern": "started server on .+, url: (https?://.+)",
"uriFormat": "%s",
"action": "debugWithChrome"
}
}
]
}
9 changes: 9 additions & 0 deletions examples/vercel-commerce/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit",
"source.sortMembers": "explicit"
}
}
72 changes: 72 additions & 0 deletions examples/vercel-commerce/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fcommerce&project-name=commerce&repo-name=commerce&demo-title=Next.js%20Commerce&demo-url=https%3A%2F%2Fdemo.vercel.store&demo-image=https%3A%2F%2Fbigcommerce-demo-asset-ksvtgfvnd.vercel.app%2Fbigcommerce.png&env=COMPANY_NAME,SHOPIFY_REVALIDATION_SECRET,SHOPIFY_STORE_DOMAIN,SHOPIFY_STOREFRONT_ACCESS_TOKEN,SITE_NAME,TWITTER_CREATOR,TWITTER_SITE)

# Next.js Commerce

A high-perfomance, server-rendered Next.js App Router ecommerce application.

This template uses React Server Components, Server Actions, `Suspense`, `useOptimistic`, and more.

<h3 id="v1-note"></h3>

> Note: Looking for Next.js Commerce v1? View the [code](https://github.com/vercel/commerce/tree/v1), [demo](https://commerce-v1.vercel.store), and [release notes](https://github.com/vercel/commerce/releases/tag/v1).

## Providers

Vercel will only be actively maintaining a Shopify version [as outlined in our vision and strategy for Next.js Commerce](https://github.com/vercel/commerce/pull/966).

Vercel is happy to partner and work with any commerce provider to help them get a similar template up and running and listed below. Alternative providers should be able to fork this repository and swap out the `lib/shopify` file with their own implementation while leaving the rest of the template mostly unchanged.

- Shopify (this repository)
- [BigCommerce](https://github.com/bigcommerce/nextjs-commerce) ([Demo](https://next-commerce-v2.vercel.app/))
- [Ecwid by Lightspeed](https://github.com/Ecwid/ecwid-nextjs-commerce/) ([Demo](https://ecwid-nextjs-commerce.vercel.app/))
- [Medusa](https://github.com/medusajs/vercel-commerce) ([Demo](https://medusa-nextjs-commerce.vercel.app/))
- [Saleor](https://github.com/saleor/nextjs-commerce) ([Demo](https://saleor-commerce.vercel.app/))
- [Shopware](https://github.com/shopwareLabs/vercel-commerce) ([Demo](https://shopware-vercel-commerce-react.vercel.app/))
- [Swell](https://github.com/swellstores/verswell-commerce) ([Demo](https://verswell-commerce.vercel.app/))
- [Umbraco](https://github.com/umbraco/Umbraco.VercelCommerce.Demo) ([Demo](https://vercel-commerce-demo.umbraco.com/))
- [Wix](https://github.com/wix/nextjs-commerce) ([Demo](https://wix-nextjs-commerce.vercel.app/))

> Note: Providers, if you are looking to use similar products for your demo, you can [download these assets](https://drive.google.com/file/d/1q_bKerjrwZgHwCw0ovfUMW6He9VtepO_/view?usp=sharing).

## Integrations

Integrations enable upgraded or additional functionality for Next.js Commerce

- [Orama](https://github.com/oramasearch/nextjs-commerce) ([Demo](https://vercel-commerce.oramasearch.com/))

- Upgrades search to include typeahead with dynamic re-rendering, vector-based similarity search, and JS-based configuration.
- Search runs entirely in the browser for smaller catalogs or on a CDN for larger.

- [React Bricks](https://github.com/ReactBricks/nextjs-commerce-rb) ([Demo](https://nextjs-commerce.reactbricks.com/))
- Edit pages, product details, and footer content visually using [React Bricks](https://www.reactbricks.com) visual headless CMS.

## Running locally

You will need to use the environment variables [defined in `.env.example`](.env.example) to run Next.js Commerce. It's recommended you use [Vercel Environment Variables](https://vercel.com/docs/concepts/projects/environment-variables) for this, but a `.env` file is all that is necessary.

> Note: You should not commit your `.env` file or it will expose secrets that will allow others to control your Shopify store.

1. Install Vercel CLI: `npm i -g vercel`
2. Link local instance with Vercel and GitHub accounts (creates `.vercel` directory): `vercel link`
3. Download your environment variables: `vercel env pull`

```bash
pnpm install
pnpm dev
```

Your app should now be running on [localhost:3000](http://localhost:3000/).

<details>
<summary>Expand if you work at Vercel and want to run locally and / or contribute</summary>

1. Run `vc link`.
1. Select the `Vercel Solutions` scope.
1. Connect to the existing `commerce-shopify` project.
1. Run `vc env pull` to get environment variables.
1. Run `pnpm dev` to ensure everything is working correctly.
</details>

## Vercel, Next.js Commerce, and Shopify Integration Guide

You can use this comprehensive [integration guide](https://vercel.com/docs/integrations/ecommerce/shopify) with step-by-step instructions on how to configure Shopify as a headless CMS using Next.js Commerce as your headless Shopify storefront on Vercel.
12 changes: 12 additions & 0 deletions examples/vercel-commerce/app/[page]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Footer from 'components/layout/footer';

export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<div className="w-full">
<div className="mx-8 max-w-2xl py-20 sm:mx-auto">{children}</div>
</div>
<Footer />
</>
);
}
11 changes: 11 additions & 0 deletions examples/vercel-commerce/app/[page]/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import OpengraphImage from 'components/opengraph-image';
import { getPage } from 'lib/shopify';

export const runtime = 'edge';

export default async function Image({ params }: { params: { page: string } }) {
const page = await getPage(params.page);
const title = page.seo?.title || page.title;

return await OpengraphImage({ title });
}
45 changes: 45 additions & 0 deletions examples/vercel-commerce/app/[page]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { Metadata } from 'next';

import Prose from 'components/prose';
import { getPage } from 'lib/shopify';
import { notFound } from 'next/navigation';

export async function generateMetadata({
params
}: {
params: { page: string };
}): Promise<Metadata> {
const page = await getPage(params.page);

if (!page) return notFound();

return {
title: page.seo?.title || page.title,
description: page.seo?.description || page.bodySummary,
openGraph: {
publishedTime: page.createdAt,
modifiedTime: page.updatedAt,
type: 'article'
}
};
}

export default async function Page({ params }: { params: { page: string } }) {
const page = await getPage(params.page);

if (!page) return notFound();

return (
<>
<h1 className="mb-8 text-5xl font-bold">{page.title}</h1>
<Prose className="mb-8" html={page.body as string} />
<p className="text-sm italic">
{`This document was last updated on ${new Intl.DateTimeFormat(undefined, {
year: 'numeric',
month: 'long',
day: 'numeric'
}).format(new Date(page.updatedAt))}.`}
</p>
</>
);
}
6 changes: 6 additions & 0 deletions examples/vercel-commerce/app/api/revalidate/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { revalidate } from 'lib/shopify';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest): Promise<NextResponse> {
return revalidate(req);
}
19 changes: 19 additions & 0 deletions examples/vercel-commerce/app/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client';

export default function Error({ reset }: { reset: () => void }) {
return (
<div className="mx-auto my-4 flex max-w-xl flex-col rounded-lg border border-neutral-200 bg-white p-8 md:p-12 dark:border-neutral-800 dark:bg-black">
<h2 className="text-xl font-bold">Oh no!</h2>
<p className="my-2">
There was an issue with our storefront. This could be a temporary issue, please try your
action again.
</p>
<button
className="mx-auto mt-4 flex w-full items-center justify-center rounded-full bg-blue-600 p-4 tracking-wide text-white hover:opacity-90"
onClick={() => reset()}
>
Try Again
</button>
</div>
);
}
Binary file added examples/vercel-commerce/app/favicon.ico
Binary file not shown.
21 changes: 21 additions & 0 deletions examples/vercel-commerce/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@media (prefers-color-scheme: dark) {
html {
color-scheme: dark;
}
}

@supports (font: -apple-system-body) and (-webkit-appearance: none) {
img[loading='lazy'] {
clip-path: inset(0.6px);
}
}

a,
input,
button {
@apply focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400 focus-visible:ring-offset-2 focus-visible:ring-offset-neutral-50 dark:focus-visible:ring-neutral-600 dark:focus-visible:ring-offset-neutral-900;
}
52 changes: 52 additions & 0 deletions examples/vercel-commerce/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { CartProvider } from 'components/cart/cart-context';
import { Navbar } from 'components/layout/navbar';
import { GeistSans } from 'geist/font/sans';
import { getCart } from 'lib/shopify';
import { ensureStartsWith } from 'lib/utils';
import { cookies } from 'next/headers';
import { ReactNode } from 'react';
import './globals.css';

const { TWITTER_CREATOR, TWITTER_SITE, SITE_NAME } = process.env;
const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL
? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`
: 'http://localhost:3000';
const twitterCreator = TWITTER_CREATOR ? ensureStartsWith(TWITTER_CREATOR, '@') : undefined;
const twitterSite = TWITTER_SITE ? ensureStartsWith(TWITTER_SITE, 'https://') : undefined;

export const metadata = {
metadataBase: new URL(baseUrl),
title: {
default: SITE_NAME!,
template: `%s | ${SITE_NAME}`
},
robots: {
follow: true,
index: true
},
...(twitterCreator &&
twitterSite && {
twitter: {
card: 'summary_large_image',
creator: twitterCreator,
site: twitterSite
}
})
};

export default async function RootLayout({ children }: { children: ReactNode }) {
const cartId = cookies().get('cartId')?.value;
// Don't await the fetch, pass the Promise to the context provider
const cart = getCart(cartId);

return (
<html lang="en" className={GeistSans.variable}>
<body className="bg-neutral-50 text-black selection:bg-teal-300 dark:bg-neutral-900 dark:text-white dark:selection:bg-pink-500 dark:selection:text-white">
<CartProvider cartPromise={cart}>
<Navbar />
<main>{children}</main>
</CartProvider>
</body>
</html>
);
}
7 changes: 7 additions & 0 deletions examples/vercel-commerce/app/opengraph-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import OpengraphImage from 'components/opengraph-image';

export const runtime = 'edge';

export default async function Image() {
return await OpengraphImage();
}
20 changes: 20 additions & 0 deletions examples/vercel-commerce/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Carousel } from 'components/carousel';
import { ThreeItemGrid } from 'components/grid/three-items';
import Footer from 'components/layout/footer';

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

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