快速入门 Supabase
简介
Supabase 是一个开源的 Firebase 替代品。
本快速入门是一个简单的示例,展示如何将 Supabase 与 Plasmo 结合使用。
先决条件
- Supabase (opens in a new tab) 账户
- Supabase 项目
使用 Supabase 初始化 Plasmo 项目
pnpm create plasmo --with-supabase
设置环境变量
为了使 Supabase 正常工作,我们需要定义一个 URL 和一个 KEY。
你可以在 Supabase 项目仪表板中找到它们:
让我们在 .env
文件中添加它们:
PLASMO_PUBLIC_SUPABASE_URL="更改我"
PLASMO_PUBLIC_SUPABASE_KEY="更改我"
Supabase 存储库
我们需要初始化 Supabase,因此让我们添加一个名为 core/supabase.ts
的文件:
import { createClient } from "@supabase/supabase-js"
import { Storage } from "@plasmohq/storage"
const storage = new Storage({
area: "local"
})
export const supabase = createClient(
process.env.PLASMO_PUBLIC_SUPABASE_URL,
process.env.PLASMO_PUBLIC_SUPABASE_KEY,
{
auth: {
storage,
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: true
}
}
)
添加重定向 URL
当用户注册时,他们需要确认他们的电子邮件。为此,我们需要为我们的 Supabase 项目添加一个重定向 URL。
首先,我们需要为开发创建一个一致的扩展 ID。当你推送到不同的网络商店时,你会得到一个不同的 ID。要了解所有这些是如何工作的,请查看我们关于创建一致的扩展 ID (opens in a new tab)的博客文章。
前往 Itero KeyPair 工具 (opens in a new tab)生成你的扩展 ID。
我们可以将 ID 和公钥存储在我们的 .env
文件中:
CRX_ID="替换为 Itero KeyPair 工具提供的 CRX ID 值"
CRX_KEY="替换为 Itero KeyPair 工具提供的公钥值"
然后,在你的 package.json
中引用公钥作为 manifest.key
值:
"manifest": {
"host_permissions": [
"https://*/*"
],
"key": "$CRX_KEY",
}
现在我们需要确保浏览器不会阻止对选项页面的访问。为此,我们必须将其添加到清单中的 web_accessible_resources
:
"web_accessible_resources": [
{
"resources": [
"options.html"
],
"matches": [
"<all_urls>"
],
"extension_ids": [
"$CRX_ID"
]
}
]
前往 Supabase 控制台并点击“身份验证”选项卡,然后点击 URL 配置。
现在在站点 URL 和重定向 URL 中添加以下 URL:
chrome-extension://<CRX_ID>/options.html
将 CRX_ID
替换为 Itero KeyPairs 工具或生产网络商店给你的实际扩展 ID。
与 React 组件集成
现在我们可以在 React 组件中编写代码,利用 Supabase!
这里是一个使用 Supabase 在扩展选项页面中的 React 组件示例。
import type { Provider, User } from "@supabase/supabase-js"
import { useEffect, useState } from "react"
import { Storage } from "@plasmohq/storage"
import { useStorage } from "@plasmohq/storage/hook"
import { supabase } from "~core/supabase"
function IndexOptions() {
const [user, setUser] = useStorage<User>({
key: "user",
instance: new Storage({
area: "local"
})
})
const [username, setUsername] = useState("")
const [password, setPassword] = useState("")
useEffect(() => {
async function init() {
const { data, error } = await supabase.auth.getSession()
if (error) {
console.error(error)
return
}
if (!!data.session) {
setUser(data.session.user)
}
}
init()
}, [])
const handleEmailLogin = async (
type: "LOGIN" | "SIGNUP",
username: string,
password: string
) => {
try {
const {
error,
data: { user }
} =
type === "LOGIN"
? await supabase.auth.signInWithPassword({
email: username,
password
})
: await supabase.auth.signUp({ email: username, password })
if (error) {
alert("身份验证错误: " + error.message)
} else if (!user) {
alert("注册成功,确认邮件应该很快发送!")
} else {
setUser(user)
}
} catch (error) {
console.log("error", error)
alert(error.error_description || error)
}
}
const handleOAuthLogin = async (provider: Provider, scopes = "email") => {
await supabase.auth.signInWithOAuth({
provider,
options: {
scopes,
redirectTo: location.href
}
})
}
return (
<main
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
width: "100%",
top: 240,
position: "relative"
}}>
<div
style={{
display: "flex",
flexDirection: "column",
width: 240,
justifyContent: "space-between",
gap: 4.2
}}>
{user && (
<>
<h3>
{user.email} - {user.id}
</h3>
<button
onClick={() => {
supabase.auth.signOut()
setUser(null)
}}>
登出
</button>
</>
)}
{!user && (
<>
<label>邮箱</label>
<input
type="text"
placeholder="您的用户名"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<label>密码</label>
<input
type="password"
placeholder="您的密码"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button
onClick={(e) => {
handleEmailLogin("SIGNUP", username, password)
}}>
注册
</button>
<button
onClick={(e) => {
handleEmailLogin("LOGIN", username, password)
}}>
登录
</button>
<button
onClick={(e) => {
handleOAuthLogin("github")
}}>
使用 GitHub 登录
</button>
</>
)}
</div>
</main>
)
}
export default IndexOptions
完整示例
要查看完整的示例,请查看我们示例仓库中的 with-supabase (opens in a new tab)。