前端秒变全栈:Vue3 + Supabase 三小时交付完整应用,后端一行不写
【免费下载链接】supabaseThe Postgres development platform. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications.项目地址: https://gitcode.com/GitHub_Trending/supa/supabase
"我只写前端,后端怎么办?"这是无数 Vue 开发者在个人项目、独立出海、内部工具、黑客松 Demo 上反复撞见的墙。传统方案要么引入 Node 服务端把工程复杂度翻倍,要么使用云函数把逻辑拆得七零八落,要么退回 Firebase 接受锁死生态和 SQL 能力阉割。
Supabase 给出的答案是另一条路:让 PostgreSQL 自己成为后端。它把数据库、REST API、实时订阅、认证、对象存储和边缘函数打包成一套开箱即用的 BaaS,前端只要装一个 JS SDK 就能拿到完整的后端能力。这个定位让它在 2025–2026 年踩中了风口——社区讨论中它被称作"Vibe Coding 的默认后端",估值已突破百亿美元,还以 1.5 亿美元融资收购了数据库公司 Turso,把目光投向"AI 智能体需要数百万个独立数据库"的下一程。
本文不再复述营销话术,而是直接打开 Supabase 官方仓库(supabase/supabase)中真实的 Vue 3 示例代码,从项目初始化、数据库表设计、认证、CRUD、文件存储到本地联调与上线部署,把"三小时交付完整应用"的完整链路拆给你看,并交代每一环背后"为什么能这么省"的机制原理。
一张表就是一套 API:BaaS 的底气从哪来
先看仓库里最核心的示例:examples/user-management/vue3-user-management。这是一个官方维护的完整 Vue 3 用户管理应用,功能清单极其克制,却覆盖了全栈应用的三大命脉:
- 通过 Magic Link(邮箱魔法链接)登录,无需密码;
- 读取、更新用户档案数据(数据库 CRUD);
- 上传、回显头像图片(对象存储)。
整个项目的前端依赖只有两个,见 package.json:
"dependencies": { "@supabase/supabase-js": "^2", "vue": "^3.5.30" }没有 Express、没有 ORM、没有鉴权中间件。后端能力的秘密藏在架构里:Supabase 在 PostgreSQL 之上叠了一层PostgREST——一个把数据库表直接暴露为 RESTful API 的网关。你在数据库里建一张表,PostgREST 就自动生成GET/POST/PATCH/DELETE端点;你在表上定义行级安全(RLS)策略,这个 API 就自带权限语义。前端拿到的supabase.from('profiles').select(...)这样的链式调用,底层打的正是这些自动生成的 HTTP 接口。
这也解释了为什么仓库的 Docker 自托管编排(docker/docker-compose.yml)里躺着十来个相互咬合的服务:Studio 控制台、基于 Envoy 的 API 网关api-gw、负责 JWT 认证的auth(GoTrue)、把 Postgres 变成 REST API 的 PostgREST、负责 WebSocket 广播的 Realtime、对象存储 Storage、连接池 Supavisor 等等。开发者感知到的"一个 BaaS",其实是一套企业级开源组件堆叠出的平台——这也是它与 Firebase 最本质的区别:底层是标准 SQL 和你能完全掌控的 Postgres。
第一步:脚手架、环境变量与数据库表设计
按官方 Quickstart(apps/docs/content/guides/getting-started/quickstarts/vue.mdx)的流程,从零初始化一个 Vue 应用只需三行命令:
npm create vite@latest supabase-vue-3 -- --template vue cd supabase-vue-3 npm install @supabase/supabase-js然后把项目 URL 与 publishable key 写入.env(参考示例中的 .env.example):
VITE_SUPABASE_URL=https://your-project-ref.supabase.co VITE_SUPABASE_PUBLISHABLE_KEY=your-publishable-key初始化客户端的代码全项目只有五行的量级,见 src/supabase.js:
import { createClient } from '@supabase/supabase-js' const supabaseUrl = import.meta.env.VITE_SUPABASE_URL const supabasePublishableKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY export const supabase = createClient(supabaseUrl, supabasePublishableKey)值得注意:这两个变量会暴露在浏览器里,官方文档对此的注释是"这没问题,因为数据库开启了行级安全(RLS)"。这句话是整篇文章的安全主线,后面会展开。
接下来是整条链路里唯一一次"写后端"的环节——但用的不是编程语言,而是 SQL。示例 README(README.md)给出了完整的建表脚本,核心是一张profiles表:
create table profiles ( id uuid references auth.users not null, updated_at timestamp with time zone, username text unique, avatar_url text, website text, primary key (id), unique(username), constraint username_length check (char_length(username) >= 3) );三个细节值得工程师品一品:
- 主键直接引用
auth.users:id是 UUID 且外键指向 Supabase 内置的认证用户表,登录用户与业务数据的绑定关系由数据库约束兜底; - 约束写在数据库里:
username唯一、长度不小于 3,这类校验不需要前端或中间层重复实现,任何绕过 UI 的请求都在数据库层被拦截; - 表结构即 API 契约:建完表,PostgREST 立即暴露对应的 REST 端点,
select、insert、update全部可用——这就是"后端一行不写"的字面含义。
建表动作既可以在云端的 SQL Editor 里执行,也可以在本地supabase migration new生成的迁移文件中维护,后者让表结构像前端代码一样进入版本管理。
认证打通:Magic Link 登录与登录态管理
认证是新手最容易写崩的部分:密码哈希、会话令牌、过期刷新、安全 Cookie……Supabase Auth 把这些全部内置。示例使用邮箱魔法链接,前端交互代码只有Auth.vue一个组件(src/components/Auth.vue):
const handleLogin = async () => { try { loading.value = true const { error } = await supabase.auth.signInWithOtp({ email: email.value }) if (error) throw error alert('Check your email for the login link!') } catch (error) { if (error instanceof Error) { alert(error.message) } } finally { loading.value = false } }用户提交邮箱后,Auth 服务签发一次性链接发送到邮箱,点击即完成登录。而"当前是否已登录"的全局状态,由 src/App.vue 监听维护:
onMounted(() => { supabase.auth.getClaims().then(({ data }) => { claims.value = data.claims }) supabase.auth.onAuthStateChange(async () => { const { data } = await supabase.auth.getClaims() claims.value = data.claims }) })<Account v-if="claims" :claims="claims" /> <Auth v-else />getClaims()读取 JWT 中的声明,onAuthStateChange订阅登录/登出事件——登录态在页面刷新、跨标签页、Token 过期等场景下都由 SDK 自动维护。需要社交登录时,官方仓库还提供了 GitHub OAuth 的完整配置流程,社区文章对此也有大量实践,原理一致:在 GitHub 侧创建 OAuth App,把回调地址填进 Supabase 控制台,前端一行signInWithOAuth即可。
这里有一层值得 Vue 开发者留意的机制:JWT 的sub声明(用户 UUID)与数据库 RLS 中的auth.uid()是同一枚 Token 的两种读取视角。前端从claims.sub拿用户 ID 去查询自己的档案,数据库策略用auth.uid()校验请求归属——两端基于同一签名体系,这就是"无需后端代码却能完成身份鉴权"的底层密码。
CRUD 与安全底线:RLS 是一切的根基
登录之后,档案的读取与更新落在 src/components/Account.vue,两段代码分别是读和写:
let { data, error, status } = await supabase .from('profiles') .select(`username, website, avatar_url`) .eq('id', claims.value.sub) .single()const updates = { id: claims.value.sub, username: username.value, website: website.value, avatar_url: avatar_url.value, updated_at: new Date(), } let { error } = await supabase.from('profiles').upsert(updates)select加.eq('id', ...)过滤、upsert一键插入或更新——标准的前端链式调用,没有一行服务端逻辑。但真正决定"谁能读、谁能写"的,是建表时跟着写下的那三条 RLS 策略:
alter table profiles enable row level security; create policy "Public profiles are viewable by everyone." on profiles for select using ( true ); create policy "Users can insert their own profile." on profiles for insert with check ( (select auth.uid()) = id ); create policy "Users can update own profile." on profiles for update using ( (select auth.uid()) = id );语义一目了然:档案公开可读;只有auth.uid()等于记录id的用户本人能插入和更新自己的档案。RLS 是 Postgres 原生机制,策略在数据库内部执行,任何途径(REST API、直接 SQL 连接、未来新增的客户端)都无法绕过——这正是"publishable key 可以安全暴露在浏览器里"的前提。
反过来,忽略这一层就会付出真实代价:2025 年 UpGuard 安全团队的研究发现,全网有16,326 个 Supabase 项目暴露了公开可读取的数据库表,其中不少包含个人数据,TechCrunch 等媒体对此做了报道。这些项目的共性失误高度一致——建了表、接入了 SDK,却忘了enable row level security和策略。把 RLS 当作"可选的进阶功能"是 BaaS 时代最危险的认知偏差;在你写下create table之后的第一件事,就应该是打开 RLS。
文件存储:三行代码搞定头像上传
档案里还躺着一个avatar_url字段,对应存储层的能力。头像上传组件 src/components/Avatar.vue 展示了 Storage 的完整闭环——上传与下载:
let { error: uploadError } = await supabase.storage .from('avatars') .upload(filePath, file)const { data, error } = await supabase.storage .from('avatars') .download(path.value) src.value = URL.createObjectURL(data)上传用的是随机文件名,下载后在浏览器侧URL.createObjectURL生成本地预览,避免每次渲染都走一遍网络。桶(Bucket)的权限同样在 SQL 中声明:
insert into storage.buckets (id, name) values ('avatars', 'avatars'); create policy "Avatar images are publicly accessible." on storage.objects for select using ( bucket_id = 'avatars' ); create policy "Anyone can upload an avatar." on storage.objects for insert with check ( bucket_id = 'avatars' );Storage 对公众开放读(头像需要公开访问)、放行登录用户上传,权限模型和数据库表完全一致地由策略驱动。更进阶的做法是把上传 URL 签名化、给对象加防盗链,或接入 CDN 做边缘缓存——能力都在,只是按需开启。
至此,"认证、CRUD、文件存储"三大件已经全部打通。把Auth、Account、Avatar三个组件组装进App.vue,npm run dev启动 Vite 开发服务器,浏览器打开localhost:5173,一个完整的用户管理应用就出现在眼前——这正是官方教程(with-vue-3.mdx)里"At this stage you have a fully functional application!"的由来。
顺带一提,这套用户管理脚手架在仓库里以九种技术栈平行存在——React、Svelte、Swift、Flutter、Angular、Ionic,乃至 Solid 和 Nuxt——它们共享同一套数据库、同一份 RLS 策略、同一套 Storage 配置。后端能力与前端框架彻底解耦,这是"前端秒变全栈"最有力的注脚:你学的不是某个框架绑定的后端,而是一套可复用的后端资产。
从本地联调到上线部署:两条路线都讲清楚
应用写完了,接下来是工程师最关心的最后一公里。Supabase 给了两条部署路线,恰好对应不同的控制欲与运维成本。
路线 A:托管云(默认路径)。在控制台创建项目、执行建表 SQL、拿到 URL 和 key 之后,前端npm run build产出静态资源,部署到任意静态托管(Vercel、Netlify、自有服务器)即可。数据库、Auth、Storage 全部由平台托管,自动备份、免运维。这也是"三小时交付"最顺滑的路径——本地开发与生产环境共享同一套 API,除了环境变量不同,代码路径完全一致。
路线 B:自托管(Docker Compose)。仓库根目录的 docker/ 提供了官方自托管编排。它把完整服务栈收进一份docker-compose.yml:Studio 控制台、Envoy API 网关、Auth、PostgREST、Realtime、Storage、Postgres 元数据管理、Postgres 本体、Edge Runtime、日志链路(Logflare + Vector)和连接池 Supavisor。社区里的 Windows 部署与本地联调文章走的也是这条路——装好 Docker 与 Supabase CLI,supabase start即可拉起本地实例,.env指向localhost完成联调。
日常运维则被封装成脚本(docker/run.sh):
sh run.sh start # docker compose up -d --wait sh run.sh status # docker compose ps sh run.sh logs auth # 跟踪指定服务日志 sh run.sh secrets # 打印密钥与 API Key sh update.sh # 备份后升级整套服务自托管的代价在 docker/README.md 里被写得很直白——默认配置不安全,不能直接上生产:必须更换所有默认密码与密钥、复查 CORS 配置、在服务前方架设 HTTPS 反向代理、并建立备份机制。托管云替你承担了这部分运维风险,自托管则把控制权与责任同时交还给你。对大多数个人项目和早期产品,路线 A 是正确的默认选择;对数据主权敏感或需要深度定制的场景,路线 B 才是答案。
三小时背后的工程真相
复盘整条链路,会发现"三小时交付"不是营销话术,而是有清晰机制支撑的工程事实:
- 表即 API:PostgREST 把 DDL 变成 REST 端点,省掉一整层路由与序列化代码;
- 数据库内嵌鉴权:RLS 策略让权限逻辑沉淀在数据层,任何客户端路径都无法绕过;
- 状态与会话由 SDK 接管:
onAuthStateChange、getClaims、Token 刷新都藏在supabase-js内部; - 存储与数据库共用同一权限心智:一条
policy同时约束表和桶,学习成本被压缩到最小。
当然,边界也要说清楚。BaaS 能覆盖的是"标准的 CRUD + 认证 + 存储"形态;当业务逻辑复杂到需要跨表事务编排、定时任务、第三方回调签名验证时,就需要 Supabase Edge Functions(基于 Deno 的云端函数)或直接在数据库里写存储过程——这些依然是"后端",只是换了一种更贴近数据层的写法。RLS 是最后一道防线,也意味着它必须成为第一道防线——那 1.6 万个裸奔的数据库,就是给所有"只写前端"的开发者上的最贵一课。
如果你正打算用 Vue 3 做一个带账号体系的完整应用,不妨直接把examples/user-management/vue3-user-management拉下来跑一遍:初始化、建表、魔法链接登录、档案 CRUD、头像上传,再到npm run dev看到完整应用在 5173 端口跑起来——这条路径上的每一步,仓库里都有真实可运行的代码等着你。剩下的三小时里,你会发现自己省下的不是"写后端的时间",而是整整一类工程问题。
【免费下载链接】supabaseThe Postgres development platform. Supabase gives you a dedicated Postgres database to build your web, mobile, and AI applications.项目地址: https://gitcode.com/GitHub_Trending/supa/supabase
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考