Cal.com 推出使用 Next.js 和 Supabase 构建的专家市场
与普遍的看法相反,由于现代史上最大的在线牛肉营销活动,Cal.com 和 Supabase 实际上是非常好的朋友,他们共同的使命是构建开源软件。
因此,当 Cal.com 团队联系我们,希望我们能合作开发他们的新平台入门套件时,我们非常高兴。我们终于可以合作发布 Product Hunt,而不是相互竞争了。
什么是堆栈?
最初,该应用程序是为在 SQLite 上运行而构建的。然而,当需求增长到包括文件存储时,Cal.com 团队想起了他们的宿敌 Supabase,幸运的是,多亏了 Prisma 和 Supabase,在发布前三天将一切都切换到 Postgres 轻而易举。
Prisma 配置用于 Supabase 上的 Postgres #
使用 Prisma 时,您的应用程序将直接连接到 Supabase 上托管的 Postgres 数据库。为了有效地处理连接管理,尤其是在使用 Next.js 等无服务器应用程序时,Supabase 提供了一个名为Supavisor的连接池,以确保您的数据库在流量增加的情况下高效运行。
配置schema.prisma
在您提供以下连接字符串的文件中指定:
schema.prisma
datasource db {
provider = "postgresql"
url = env("POSTGRES_PRISMA_URL")
directUrl = env("POSTGRES_URL_NON_POOLING")
schemas = ["prisma"] // see multi-schema support below
}
.env
这将从你的文件中加载相关的 Supabase 连接字符串
.env
POSTGRES_PRISMA_URL="postgres://postgres.YOUR-PROJECT-REF:[YOUR-PASSWORD]@aws-0-[REGION].pooler.supabase.com:6543/postgres?pgbouncer=true&connection_limit=1" # Transaction Mode
POSTGRES_URL_NON_POOLING="postgres://postgres.YOUR-PROJECT-REF:[YOUR-PASSWORD]@aws-0-[REGION].pooler.supabase.com:5432/postgres" # Session Mode
您可以在Supabase 仪表板的数据库设置中找到这些值。
有关将 Prisma 与 Supabase 结合使用的更多详细信息,请阅读官方文档。
Prisma中的多模式支持
在 Supabase 中,模式通过自动生成的PostgRESTpublic
API公开,这允许您使用Supabase 客户端库(例如supabase-js)从任何使用 HTTPS 的环境连接到您的数据库。
由于 Prisma 直接连接到您的数据库,因此建议将您的数据放在未通过 API 公开的单独模式上。
multischema
我们可以通过在文件中启用支持来实现这一点schema.prisma
:
schema.prisma
generator client {
provider = "prisma-client-js"
previewFeatures = ["multiSchema"]
}
model Account {
id String @id @default(cuid())
// ...
@@schema("prisma")
}
使用 React Dropzone 和 Supabase Storage 上传个人资料图片
Supabase Storage是一个与 S3 兼容的基于云的对象存储,可让您安全地存储文件。它与Supabase Auth方便地集成,让您可以轻松限制上传和下载的访问权限。
Cal.com 的平台入门套件在 Next.js 的Auth.js上运行其身份验证。幸运的是,Supabase Storage 非常灵活,允许您轻松在服务器端创建签名的上传 URL,然后从客户端上传资产 - 无论您选择使用哪种技术来处理应用程序的身份验证。
为了实现这一点,我们可以在 Next.js 中创建一个 API 路由来生成这些签名的 URL:
src/app/api/supabase/storage/route.ts
import { auth } from '@/auth'
import { env } from '@/env'
import { createClient } from '@supabase/supabase-js'
export const dynamic = 'force-dynamic' // defaults to auto
export async function GET(request: Request) {
try {
const session = await auth()
if (!session || !session.user.id) {
return new Response('Unauthorized', { status: 401 })
}
const {
user: { id },
} = session
// Generate signed upload url to use on client.
const supabaseAdmin = createClient(env.NEXT_PUBLIC_SUPABASE_URL, env.SUPABASE_SERVICE_ROLE_KEY)
const { data, error } = await supabaseAdmin.storage
.from('avatars')
.createSignedUploadUrl(id, { upsert: true })
console.log(error)
if (error) throw error
return new Response(JSON.stringify(data), {
status: 200,
})
} catch (e) {
console.error(e)
return new Response('Internal Server Error', { status: 500 })
}
}
该createSignedUploadUrl
方法返回一个token
,然后我们可以在客户端使用它来上传React Dropzone选择的文件:
src/app/dashboard/settings/_components/ supabase-react-dropzone.tsx
'use client'
import { env } from '@/env'
import { createClient } from '@supabase/supabase-js'
import Image from 'next/image'
import React, { useState } from 'react'
import { useDropzone } from 'react-dropzone'
export default function SupabaseReactDropzone({ userId }: { userId?: string } = {}) {
const supabaseBrowserClient = createClient(
env.NEXT_PUBLIC_SUPABASE_URL,
env.NEXT_PUBLIC_SUPABASE_ANON_KEY
)
const { acceptedFiles, fileRejections, getRootProps, getInputProps } = useDropzone({
maxFiles: 1,
accept: {
'image/jpeg': [],
'image/png': [],
},
onDropAccepted: async (acceptedFiles) => {
setAvatar(null)
console.log(acceptedFiles)
const { path, token }: { path: string; token: string } = await fetch(
'/api/supabase/storage'
).then((res) => res.json())
const { data, error } = await supabaseBrowserClient.storage
.from('avatars')
.uploadToSignedUrl(path, token, acceptedFiles[0])
},
})
return (
<div className="mx-auto mt-4 grid w-full gap-2">
<div {...getRootProps({ className: 'dropzone' })}>
<input {...getInputProps()} />
<p>Drag 'n' drop some files here, or click to select files</p>
<em>(Only *.jpeg and *.png images will be accepted)</em>
</div>
</div>
)
}
用于 Supabase Storage的自定义 Next.js 图像加载器
Supabase Storage 还可以通过创建自定义加载器方便地与 Next.js 图像范例集成:
src/lib/ supabase-image-loader.ts
import { env } from '@/env'
export default function supabaseLoader({ src, width, quality }) {
return `${env.NEXT_PUBLIC_SUPABASE_URL}/storage/v1/object/public/${src}?width=${width}&quality=${quality || 75}`
}
现在我们只需要在next.config.js
文件中注册自定义加载器:
next.config.js
images: {
loader: "custom",
loaderFile: "./src/lib/supabase-image-loader.ts",
},
我们只需在 Supabase Storage 中提供文件路径即可开始使用 Next.js 图像组件:
<Image
alt="Expert image"
className="aspect-square rounded-md object-cover"
src="your-bucket-name/image.png"
height="64"
width="64"
/>
Supabase Vercel Integration 可实现一键部署
Supabase 还提供了Vercel 集成,使跨分支管理环境变量和部署预览变得轻而易举。当您将 Supabase 项目连接到 Vercel 项目时,集成将使您的环境变量保持同步。
当使用Vercel 部署按钮时,集成将自动为您创建一个新的 Supabase 项目,填充环境变量,甚至运行数据库迁移和种子脚本,这意味着您可以立即启动并运行完整的端到端应用程序!
为开源做贡献
Cal.com 和 Supabase 都致力于创建开源软件,因此这个新的平台入门套件当然也是开源的,让您在几分钟内就能启动自己的市场并方便地安排时间!当然,这也意味着非常欢迎您为入门套件贡献其他功能!您可以在 GitHub 上找到存储库!
资源
转载自:https://juejin.cn/post/7383957603015917583