使用 Prisma、Supabase 和 Shadcn 设置 Next.js 项目。
设置 Next.js
首先运行以下命令,使用 supabase、typescript、tailwind 初始化下一个 js 项目:npx create-next-app@latest
。选择全部默认选项:
设置 Prisma
运行以下命令安装 prisma:npm install prisma --save-dev
安装 prisma 后,运行以下命令来初始化模式文件和 .env 文件:npx prisma init
现在应该有一个 .env 文件。你应该添加 database_url 来将 prisma 连接到你的数据库。应该如下所示:
// .env
DATABASE_URL=url
在你的 schema.prisma 中你应该添加你的模型,我现在只是使用一些随机模型:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Post {
id String @default(cuid()) @id
title String
content String?
published Boolean @default(false)
author User? @relation(fields: [authorId], references: [id])
authorId String?
}
model User {
id String @default(cuid()) @id
name String?
email String? @unique
createdAt DateTime @default(now()) @map(name: "created_at")
updatedAt DateTime @updatedAt @map(name: "updated_at")
posts Post[]
@@map(name: "users")
}
现在您可以运行以下命令将您的数据库与您的模式同步:npx prisma db push
为了在客户端访问 prisma,您需要安装 prisma 客户端。您可以通过运行以下命令来执行此操作:npm install @prisma/client
您的客户端也必须与您的模式同步,您可以通过运行以下命令来执行此操作:npx prisma generate
当你运行时,npx prisma db push
会自动调用生成命令。
为了访问 prisma 客户端,您需要创建它的一个实例,因此在 src 目录中创建一个名为 lib 的新文件夹,并向其中添加一个名为 prisma.ts 的新文件。
// prisma.ts
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export default prisma;
现在您可以在任何文件中导入相同的 Prisma 实例。
设置Shadcn
首先运行以下命令开始设置shadcn:npx shadcn-ui@latest init
我选择了以下选项:
typescript:是
样式:默认
基色:slate
全局css:src/app/globals.css
css变量:是
tailwind配置:tailwind.config.ts
组件:@/components(默认)
utils:@/lib/utils(默认)
react服务器组件:是
写入components.json:是
接下来运行以下命令来设置下一个主题:npm install next-themes
然后将一个名为 theme-provider.tsx 的文件添加到您的组件库并添加以下代码:
// theme-provider.tsx
"use client"
import * as React from "react"
import { ThemeProvider as NextThemesProvider } from "next-themes"
import { type ThemeProviderProps } from "next-themes/dist/types"
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}
设置好提供程序后,您需要将其添加到layout.tsx文件中,以便在整个应用中实现它。使用主题提供程序包装{children},如下所示:
// layout.tsx
return (
<html lang="en" suppressHydrationWarning>
<body className={inter.className}>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
{children}
</ThemeProvider>
</body>
</html>
);
现在转到 shadcn主题页面。选择要使用的主题,然后按复制代码。然后将复制的代码添加到 globals.css 中,如下所示:
// globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--card: 0 0% 100%;
--card-foreground: 224 71.4% 4.1%;
--popover: 0 0% 100%;
--popover-foreground: 224 71.4% 4.1%;
--primary: 262.1 83.3% 57.8%;
--primary-foreground: 210 20% 98%;
--secondary: 220 14.3% 95.9%;
--secondary-foreground: 220.9 39.3% 11%;
--muted: 220 14.3% 95.9%;
--muted-foreground: 220 8.9% 46.1%;
--accent: 220 14.3% 95.9%;
--accent-foreground: 220.9 39.3% 11%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 20% 98%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 262.1 83.3% 57.8%;
--radius: 0.5rem;
}
.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--card: 224 71.4% 4.1%;
--card-foreground: 210 20% 98%;
--popover: 224 71.4% 4.1%;
--popover-foreground: 210 20% 98%;
--primary: 263.4 70% 50.4%;
--primary-foreground: 210 20% 98%;
--secondary: 215 27.9% 16.9%;
--secondary-foreground: 210 20% 98%;
--muted: 215 27.9% 16.9%;
--muted-foreground: 217.9 10.6% 64.9%;
--accent: 215 27.9% 16.9%;
--accent-foreground: 210 20% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 20% 98%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--ring: 263.4 70% 50.4%;
}
}
现在您应该能够在您的项目中使用 shadcn 组件和主题。
设置 Supabase
第一步是创建一个新的 supabase 项目。接下来,安装 next.js 身份验证帮助库:npm install @supabase/auth-helpers-nextjs @supabase/supabase-js
现在,你需要将 supabase 的 URL 和匿名密钥添加到你的 .env 文件中。你的 .env 文件现在应该如下所示:
// .env
DATABASE_URL=url
NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key
我们将使用 supabase cli 根据我们的模式生成类型。使用以下命令安装该 cli:npm install supabase --save-dev
为了登录 supabase,请运行npx supabase login
它,它会自动登录。
现在我们可以通过运行以下命令来生成我们的类型:npx supabase gen types typescript --project-id YOUR_PROJECT_ID > src/lib/database.types.ts
该命令应该在您的 lib 文件夹中添加一个新文件,其中包含基于您的模式的类型。
现在在项目根目录中创建一个 middleware.ts 文件并添加以下代码:
import { createMiddlewareClient } from "@supabase/auth-helpers-nextjs";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import type { Database } from "@/lib/database.types";
export async function middleware(req: NextRequest) {
const res = NextResponse.next();
const supabase = createMiddlewareClient<Database>({ req, res });
await supabase.auth.getSession();
return res;
}
现在在应用程序目录中创建一个名为 auth 的新文件夹,然后在 auth 中创建另一个名为 callback 的文件夹,最后创建一个名为 route.ts 的文件。在该文件中添加以下代码:
// app/auth/callback/route.ts
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import type { Database } from "@/lib/database.types";
export async function GET(request: NextRequest) {
const requestUrl = new URL(request.url);
const code = requestUrl.searchParams.get("code");
if (code) {
const cookieStore = cookies();
const supabase = createRouteHandlerClient<Database>({
cookies: () => cookieStore,
});
await supabase.auth.exchangeCodeForSession(code);
}
// URL to redirect to after sign in process completes
return NextResponse.redirect(requestUrl.origin);
}
完成上述设置后,我们就可以创建一个登录页面了。在 app 目录中,创建一个名为 login 的新文件夹,其中包含一个 page.tsx 文件。
// app/login/page.tsx
"use client";
import { createClientComponentClient } from "@supabase/auth-helpers-nextjs";
import { useRouter } from "next/navigation";
import { useState } from "react";
import type { Database } from "@/lib/database.types";
export default function Login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const router = useRouter();
const supabase = createClientComponentClient<Database>();
const handleSignUp = async () => {
await supabase.auth.signUp({
email,
password,
options: {
emailRedirectTo: `${location.origin}/auth/callback`,
},
});
router.refresh();
};
const handleSignIn = async () => {
await supabase.auth.signInWithPassword({
email,
password,
});
router.refresh();
};
const handleSignOut = async () => {
await supabase.auth.signOut();
router.refresh();
};
return (
<>
<input
name="email"
onChange={(e) => setEmail(e.target.value)}
value={email}
/>
<input
type="password"
name="password"
onChange={(e) => setPassword(e.target.value)}
value={password}
/>
<button onClick={handleSignUp}>Sign up</button>
<button onClick={handleSignIn}>Sign in</button>
<button onClick={handleSignOut}>Sign out</button>
</>
);
}
现在在 auth 目录中创建一个名为 sign-up 的新文件夹,并在该文件中创建一个 route.ts 文件。添加以下代码:
// app/auth/sign-up/route.ts
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
import type { Database } from "@/lib/database.types";
export async function POST(request: Request) {
const requestUrl = new URL(request.url);
const formData = await request.formData();
const email = String(formData.get("email"));
const password = String(formData.get("password"));
const cookieStore = cookies();
const supabase = createRouteHandlerClient<Database>({
cookies: () => cookieStore,
});
await supabase.auth.signUp({
email,
password,
options: {
emailRedirectTo: `${requestUrl.origin}/auth/callback`,
},
});
return NextResponse.redirect(requestUrl.origin, {
status: 301,
});
}
在同一位置创建另一个名为 login 的文件夹。
// app/auth/login/route.ts
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
import { cookies } from "next/headers";
import { NextResponse } from "next/server";
import type { Database } from "@/lib/database.types";
export async function POST(request: Request) {
const requestUrl = new URL(request.url);
const formData = await request.formData();
const email = String(formData.get("email"));
const password = String(formData.get("password"));
const cookieStore = cookies();
const supabase = createRouteHandlerClient<Database>({
cookies: () => cookieStore,
});
await supabase.auth.signInWithPassword({
email,
password,
});
return NextResponse.redirect(requestUrl.origin, {
status: 301,
});
}
最后在同一个地方添加注销路线。
// app/auth/logout/route.ts
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'
import type { Database } from '@/lib/database.types'
export async function POST(request: Request) {
const requestUrl = new URL(request.url)
const cookieStore = cookies()
const supabase = createRouteHandlerClient<Database>({ cookies: () => cookieStore })
await supabase.auth.signOut()
return NextResponse.redirect(`${requestUrl.origin}/login`, {
status: 301,
})
}
现在,当您导航到 localhost http://localhost:3000/login时,应该有基本的登录注销注册功能。
现在,我们为下一个 js 应用程序提供了一些基本样板,其中包含 prisma shadcn 和 supabase 身份验证设置。
文章来源:https://dev.to/isaacdyor/setting-up-nextjs-project-with-prisma-200j