使用 Supabase 快速开始
介绍
Supabase 是一个开源的 Firebase 替代品。
这个快速入门是一个简单的示例,展示如何在 Plasmo 中使用 Supabase。
先决条件
- Supabase 账户
- 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 用于开发。当您推送到不同的 Web 商店时,您会得到不同的 ID。要了解更多关于这一切如何工作的信息,请查看我们关于为 Chrome 扩展创建一致 ID 的博客文章
转到 Itero KeyPair 工具 生成您的一致扩展 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,或生产 Web 商店给您的实际 ID。
与 React 组件集成
现在我们可以在 React 组件中编写使用 Supabase 的代码!
以下是在扩展选项页面的 React 组件中使用 Supabase 的示例。
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)
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 !