-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
361f2b7
commit 560ee3b
Showing
82 changed files
with
5,831 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# 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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
[![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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { CartProvider } from 'components/cart/cart-context'; | ||
import { Navbar } from 'components/layout/navbar'; | ||
import { WelcomeToast } from 'components/welcome-toast'; | ||
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 { Toaster } from 'sonner'; | ||
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} | ||
<Toaster closeButton /> | ||
<WelcomeToast /> | ||
</main> | ||
</CartProvider> | ||
</body> | ||
</html> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 /> | ||
</> | ||
); | ||
} |
Oops, something went wrong.