supabase-uniapp-adapter
v0.1.5
Published
Supabase-js 的 uniapp 兼容版本
Maintainers
Readme
supabase-js-uniapp
Supabase JS SDK 的 UniApp 适配版本。使用 uni.request 替代浏览器 fetch,让 Supabase 在微信小程序、App、H5 等 UniApp 平台上正常工作。
为什么需要这个包?
官方 @supabase/supabase-js 依赖浏览器 fetch 和 WebSocket 执行请求,且对很多浏览器的 bom 接口强依赖,在 UniApp 环境(尤其是各种小程序)中不可用。本项目通过将 HTTP 层替换为 uni.request、依据功能重新实现 auth 相关内容,完整实现了 Supabase 客户端的 API 接口。
安装
pnpm add @supabase-uni/supabase-js只需要这一个包,所有功能(数据库、认证、存储、Functions、实时订阅)都包含在内,支持 tree-shaking。
快速开始
import { createClient } from '@supabase-uni/supabase-js'
const supabase = createClient({
url: 'https://your-project.supabase.co',
anonKey: 'your-anon-key',
})使用示例
数据库查询
// 查询所有记录
const { data, error } = await supabase.from('users').select('*')
// 条件查询
const { data } = await supabase
.from('users')
.select('id, name, email')
.eq('status', 'active')
.order('created_at', { ascending: false })
.limit(10)
// 插入数据
const { data, error } = await supabase
.from('users')
.insert({ name: 'John', email: '[email protected]' })
// 更新数据
const { data, error } = await supabase
.from('users')
.update({ name: 'Jane' })
.eq('id', 1)
// 删除数据
const { error } = await supabase
.from('users')
.delete()
.eq('id', 1)
// 调用 RPC 函数
const { data, error } = await supabase.rpc('my_function', { arg1: 'value' })认证
// 邮箱密码注册
const { data, error } = await supabase.auth.signUp({
email: '[email protected]',
password: 'password123',
})
// 邮箱密码登录
const { data, error } = await supabase.auth.signInWithPassword({
email: '[email protected]',
password: 'password123',
})
// 手机号登录
const { data, error } = await supabase.auth.signInWithPassword({
phone: '13800138000',
password: 'password123',
})
// OTP 验证码登录
const { data, error } = await supabase.auth.signInWithOtp({
email: '[email protected]',
})
// OAuth 登录
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'github',
})
// 登出
const { error } = await supabase.auth.signOut()
// 获取当前用户
const { data, error } = await supabase.auth.getUser()
// App 恢复前台或需要主动兜底时,尝试刷新 token
const { data: refreshData, error: refreshError } = await supabase.auth.tryRefresh()
// 监听认证状态变化
const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
console.log(event, session)
})
// 取消监听
subscription.unsubscribe()UniApp Token 续签建议
UniApp App、小程序进入后台后,JavaScript 定时器可能暂停。建议在 App.vue 的 onShow 中调用 tryRefresh(),让应用恢复前台时主动检查当前 session:未登录会直接返回;已登录但 token 已过期或将在 60 秒内过期时,会使用 refresh_token 换取新 token。
// App.vue
import { onShow } from '@dcloudio/uni-app'
import { supabase } from '@/utils/supabase'
onShow(() => {
supabase.auth.tryRefresh().catch((error) => {
console.warn('refresh token failed', error)
})
})本库现在会在数据库、Storage、Edge Functions 请求返回 401/403 且错误内容看起来是 JWT 过期时,自动执行一次 tryRefresh() 并重试原请求一次。onShow 里的主动调用仍然建议保留,用来兜底 App 恢复前台但还没发生网络请求的场景。
onShow(() => {
supabase.auth.tryRefresh()
})文件存储
// 上传文件
const { data, error } = await supabase.storage
.from('avatars')
.upload('user-123/avatar.png', fileData)
// 下载文件
const { data, error } = await supabase.storage
.from('avatars')
.download('user-123/avatar.png')
// 获取公开 URL
const { data } = supabase.storage
.from('avatars')
.getPublicUrl('user-123/avatar.png')
// 获取签名 URL(临时访问)
const { data, error } = await supabase.storage
.from('avatars')
.createSignedUrl('user-123/avatar.png', 3600) // 1小时有效
// 列出文件
const { data, error } = await supabase.storage
.from('avatars')
.list({ limit: 10, offset: 0 })
// 删除文件
const { data, error } = await supabase.storage
.from('avatars')
.remove(['user-123/avatar.png'])
// 存储桶管理
const { data } = await supabase.storage.listBuckets()
const { data } = await supabase.storage.createBucket('new-bucket', { public: true })Edge Functions
// 调用 Edge Function
const { data, error } = await supabase.functions.invoke('hello-world', {
body: { name: 'John' },
})
// 自定义请求方法和 headers
const { data, error } = await supabase.functions.invoke('my-function', {
method: 'GET',
headers: { 'X-Custom': 'value' },
responseType: 'text',
})实时订阅
// 订阅表变更
const channel = supabase
.channel('table-changes')
.on('postgres_changes', { event: '*', schema: 'public', table: 'messages' }, (payload) => {
console.log('Change received!', payload)
})
.subscribe()
// 取消订阅
supabase.removeChannel(channel)配置选项
const supabase = createClient({
// 必填
url: 'https://xxx.supabase.co',
anonKey: 'your-anon-key',
// 可选:自定义 fetch 实现(默认使用 uni.request 适配器)
fetch: customFetchFn,
// 可选:uni.request 适配器配置
uniOptions: {
uniInstance: mockUni, // 自定义 uni 对象(用于测试或特殊平台)
timeout: 30000, // 请求超时时间(毫秒),默认 60000
debug: true, // 开启请求日志
},
// 可选:自定义请求头
headers: { 'X-Custom': 'value' },
// 可选:数据库 schema,默认 'public'
db: { schema: 'public' },
// 可选:认证配置
auth: {
autoRefreshToken: true,
persistSession: true,
storage: { // 自定义存储(默认使用 UniApp storage)
getItem: (key) => uni.getStorageSync(key),
setItem: (key, value) => uni.setStorageSync(key, value),
removeItem: (key) => uni.removeStorageSync(key),
},
},
// 可选:实时订阅配置
realtime: {
params: { eventsPerSecond: '10' },
timeout: 10000,
},
})工作原理
@supabase-uni/supabase-js
└── src/
├── request-adapter/ ← 核心:将 uni.request 封装为 fetch 兼容接口
├── postgrest/ ← PostgREST 查询构建器
├── auth/ ← 认证模块
├── storage/ ← 存储模块
├── functions/ ← Edge Functions 模块
└── realtime/ ← 实时订阅模块通过 globalThis.uni 获取 UniApp 全局对象,无需显式引入 uni-app。只要运行在 UniApp 环境中,uni 对象就自动可用。所有模块打包在一个包中,消费者的 bundler 可以通过 tree-shaking 移除未使用的代码。
平台兼容性
| 平台 | 支持状态 |
|------|---------|
| 微信小程序 | 支持 |
| H5 | 支持 |
| App(uni-app) | 支持 |
| 支付宝小程序 | 理论支持(需测试) |
| 普通浏览器/Node.js | 不支持(缺少 uni 全局对象) |
开发
# 安装依赖
pnpm install
# 构建
pnpm build
# 类型检查
pnpm typecheck发版
npm publish项目结构
supabase-js-uniapp/
├── src/
│ ├── index.ts # 入口,re-export 所有模块
│ ├── SupabaseClient.ts # 主客户端
│ ├── types.ts # 客户端配置类型
│ ├── request-adapter/ # uni.request → fetch 适配
│ ├── postgrest/ # PostgREST 查询
│ ├── auth/ # 认证
│ ├── storage/ # 文件存储
│ ├── functions/ # Edge Functions
│ └── realtime/ # 实时订阅
├── dist/ # 构建产物
├── package.json
├── tsconfig.json
└── tsup.config.tsLicense
MIT
