diff --git a/.env.example b/.env.example index 9ff0463db9..f7fa990d41 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,4 @@ 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="" diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index b3e65ae8c4..0000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,23 +0,0 @@ -module.exports = { - extends: ['next', 'prettier'], - plugins: ['unicorn'], - rules: { - 'no-unused-vars': [ - 'error', - { - args: 'after-used', - caughtErrors: 'none', - ignoreRestSiblings: true, - vars: 'all' - } - ], - 'prefer-const': 'error', - 'react-hooks/exhaustive-deps': 'error', - 'unicorn/filename-case': [ - 'error', - { - case: 'kebabCase' - } - ] - } -}; diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index b18fd29357..0000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: 2 -updates: - - package-ecosystem: 'github-actions' - directory: '/' - schedule: - interval: 'weekly' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index f2fee2f8d3..0000000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: test -on: pull_request - -# Cancel in progress workflows on pull_requests. -# https://docs.github.com/en/actions/using-jobs/using-concurrency#example-using-a-fallback-value -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - name: Set node version - uses: actions/setup-node@v3 - with: - node-version-file: '.nvmrc' - - name: Set pnpm version - uses: pnpm/action-setup@v2 - with: - run_install: false - version: 7 - - name: Cache node_modules - id: node-modules-cache - uses: actions/cache@v3 - with: - path: '**/node_modules' - key: node-modules-cache-${{ hashFiles('**/pnpm-lock.yaml') }} - - name: Install dependencies - if: steps.node-modules-cache.outputs.cache-hit != 'true' - run: pnpm install --no-frozen-lockfile - - name: Run tests - run: pnpm test diff --git a/.gitignore b/.gitignore index 0298027e4f..e82a0f9db0 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts +.env*.local diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 3c032078a4..0000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -18 diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 71df57cbc4..0000000000 --- a/.prettierignore +++ /dev/null @@ -1,3 +0,0 @@ -.vercel -.next -pnpm-lock.yaml diff --git a/.vscode/settings.json b/.vscode/settings.json index 3fbb4ab257..8345c107c1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,8 +2,8 @@ "typescript.tsdk": "node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true, "editor.codeActionsOnSave": { - "source.fixAll": true, - "source.organizeImports": true, - "source.sortMembers": true + "source.fixAll": "explicit", + "source.organizeImports": "explicit", + "source.sortMembers": "explicit" } } diff --git a/README.md b/README.md index 981685d2ba..5052aec5ba 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,10 @@ -[](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) +[](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) # Next.js Commerce -A Next.js 14 and App Router-ready ecommerce template featuring: +A high-performance, server-rendered Next.js App Router ecommerce application. -- Next.js App Router -- Optimized for SEO using Next.js's Metadata -- React Server Components (RSCs) and Suspense -- Server Actions for mutations -- Edge Runtime -- New fetching and caching paradigms -- Dynamic OG images -- Styling with Tailwind CSS -- Checkout and payments with Shopify -- Automatic light/dark mode based on system settings +This template uses React Server Components, Server Actions, `Suspense`, `useOptimistic`, and more.
@@ -27,12 +18,16 @@ Vercel is happy to partner and work with any commerce provider to help them get - 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/)) +- [Geins](https://github.com/geins-io/vercel-nextjs-commerce) ([Demo](https://geins-nextjs-commerce-starter.vercel.app/)) - [Medusa](https://github.com/medusajs/vercel-commerce) ([Demo](https://medusa-nextjs-commerce.vercel.app/)) +- [Prodigy Commerce](https://github.com/prodigycommerce/nextjs-commerce) ([Demo](https://prodigy-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/)) +- [Wix](https://github.com/wix/headless-templates/tree/main/nextjs/commerce) ([Demo](https://wix-nextjs-commerce.vercel.app/)) +- [Fourthwall](https://github.com/FourthwallHQ/vercel-commerce) ([Demo](https://vercel-storefront.fourthwall.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). @@ -41,9 +36,13 @@ Vercel is happy to partner and work with any commerce provider to help them get 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. @@ -73,4 +72,4 @@ Your app should now be running on [localhost:3000](http://localhost:3000/). ## Vercel, Next.js Commerce, and Shopify Integration Guide -You can use this comprehensive [integration guide](http://vercel.com/docs/integrations/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. +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. diff --git a/app/[page]/layout.tsx b/app/[page]/layout.tsx index 453253dca7..50614b5b16 100644 --- a/app/[page]/layout.tsx +++ b/app/[page]/layout.tsx @@ -1,15 +1,12 @@ import Footer from 'components/layout/footer'; -import { Suspense } from 'react'; export default function Layout({ children }: { children: React.ReactNode }) { return ( -
{`This document was last updated on ${new Intl.DateTimeFormat(undefined, {
year: 'numeric',
diff --git a/app/api/revalidate/route.ts b/app/api/revalidate/route.ts
index 47af2a4a4a..4ecc0b45d9 100644
--- a/app/api/revalidate/route.ts
+++ b/app/api/revalidate/route.ts
@@ -1,8 +1,6 @@
import { revalidate } from 'lib/shopify';
import { NextRequest, NextResponse } from 'next/server';
-export const runtime = 'edge';
-
export async function POST(req: NextRequest): Promise
There was an issue with our storefront. This could be a temporary issue, please try your
diff --git a/app/globals.css b/app/globals.css
index 0a6d367685..78b24be672 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -1,6 +1,17 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
+@import 'tailwindcss';
+
+@plugin "@tailwindcss/container-queries";
+@plugin "@tailwindcss/typography";
+
+@layer base {
+ *,
+ ::after,
+ ::before,
+ ::backdrop,
+ ::file-selector-button {
+ border-color: var(--color-gray-200, currentColor);
+ }
+}
@media (prefers-color-scheme: dark) {
html {
@@ -17,5 +28,5 @@
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;
+ @apply focus-visible:outline-hidden 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;
}
diff --git a/app/layout.tsx b/app/layout.tsx
index 58f5a9708e..5e3355ce90 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,15 +1,14 @@
-import Navbar from 'components/layout/navbar';
-import { GeistSans } from 'geist/font';
-import { ensureStartsWith } from 'lib/utils';
-import { ReactNode, Suspense } from 'react';
+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 { ReactNode } from 'react';
+import { Toaster } from 'sonner';
import './globals.css';
+import { baseUrl } from 'lib/utils';
-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;
+const { SITE_NAME } = process.env;
export const metadata = {
metadataBase: new URL(baseUrl),
@@ -20,25 +19,28 @@ export const metadata = {
robots: {
follow: true,
index: true
- },
- ...(twitterCreator &&
- twitterSite && {
- twitter: {
- card: 'summary_large_image',
- creator: twitterCreator,
- site: twitterSite
- }
- })
+ }
};
-export default async function RootLayout({ children }: { children: ReactNode }) {
+export default async function RootLayout({
+ children
+}: {
+ children: ReactNode;
+}) {
+ // Don't await the fetch, pass the Promise to the context provider
+ const cart = getCart();
+
return (
Oh no!
{carouselProducts.map((product, i) => (