这个免费且仅需单个文件的 Firebase Go 替代方案
BBetter Stack
Computing/SoftwareSmall Business/StartupsInternet Technology
Transcript
00:00:00PocketBase 是 Supabase 或 Firebase 的开源替代方案,也可能是你运行过的最简单的
00:00:04后端。它只需要一个文件,就能为你提供实时数据库、身份验证和
00:00:11文件存储。这与现代 Web 开发变得极其复杂的现状形成了鲜明对比。
00:00:16所以在今天的视频中,我们将测试 PocketBase,看看它的简单架构
00:00:21在构建复杂应用时是否真的经得起考验。
00:00:29PocketBase 是一个内置了 SQLite 的单一 Go 二进制文件。但实际上用 Go 语言编写代码是
00:00:35可选的,因为后端可以使用 JavaScript 和 TypeScript 进行扩展。你还会获得
00:00:40一个基础的管理后台 UI,可以在其中配置所有集合,这与 Supabase 的工作方式完全相同。
00:00:46现在谈谈架构以及你实际如何使用它。一旦 PocketBase 运行起来,你就可以
00:00:51通过 JavaScript SDK 从前端连接到它。这与 Firebase 和
00:00:57Supabase 的设计非常相似,你可以直接从前端访问数据库,而不必
00:01:02担心安全性,因为 PocketBase 有 API 规则和身份验证来确保这些规则的安全性。但让我们直接进入
00:01:08演示环节,展示一个包含身份验证、数据库和文件存储的真实应用。如果你喜欢这个
00:01:13视频,请订阅 Better Stack,我们在频道中涵盖了大量的开发者内容。
00:01:18我们这里有一个应用,后端使用了 PocketBase,前端则是用
00:01:22React 编写的 Web 前端。Web 前端中最重要的文件是这里的 pb.ts 文件,因为
00:01:30我们在其中引入了 pocketbase,创建了一个新的 PocketBase 类实例,
00:01:36然后连接到我们的后端服务。现在我们可以在应用的其余部分使用 pb 对象了。
00:01:42应用本身是一个简单的 Bug 追踪器,我们可以在列之间拖动项目,可以
00:01:48创建新的问题。如果我们查看控制登录用户的 Hook,你可以看到
00:01:53我们最初使用 pb.authStore.record 来设置状态,这将获取当前已验证的用户
00:01:59来自 PocketBase。然后我们也设置了一个监听器,如果身份验证存储通过
00:02:05onChange 事件发生变化,我们就会将新用户设置到状态中。使用起来就是这么简单。
00:02:11我们可以访问状态,也可以订阅状态,对于我们的问题数据也是如此。
00:02:16所以,在我们的 useIssues Hook 内部,我们同样初始化了一些状态,这次让它为空。
00:02:21然后我们使用 useEffect,获取所有问题并获取完整列表,然后
00:02:27我们用该列表设置问题状态,这将预先填充数据。然后我们
00:02:32也可以订阅问题数据,这样如果你在列之间拖动问题,或者创建/删除问题,
00:02:38我们可以通过 pb.collection(“issues”).subscribe 来实现,这样每当有新记录进入时,我们就可以
00:02:44将其附加到我们的状态中。这意味着当我们直接与 PocketBase 数据库交互时,
00:02:49比如拖动卡片时,状态会自动更新。在创建
00:02:54一个新问题时,我们也可以附上一张截图。让我们给应用程序截个图,
00:02:59然后点击提交问题,新问题就会出现在前端。代码中这通过
00:03:05提交函数处理,我们将所有表单数据附加在一起,最后调用 pb
00:03:11collection(“issues”).create 来传入数据。我们在后端拥有集合 API
00:03:17规则来防止滥用这些 API。PocketBase 默认会提供这个管理界面,
00:03:24在这里你可以看到我们有 users 集合和 issues 集合,
00:03:27我们所有的问题都存在这里。如果我们查看 users 集合,然后点击上方的设置,
00:03:32就会看到 API 规则选项卡,这些规则限制了对特定
00:03:37集合的访问。例如,对于用户,请求的 auth ID 不能是空字符串,当
00:03:43更新或删除用户时,ID 必须匹配已验证用户的 ID,我们可以通过
00:03:50此处的特殊字符串 “@request.auth.id” 来访问它。如果你过去使用过 Supabase,
00:03:56你会发现这种模式非常熟悉。那么如果后端不能
00:04:02完成你需要的一切怎么办?幸运的是,你可以通过 Hook 来扩展它,使用 Go,也可以使用 JavaScript
00:04:08和 TypeScript。我们可以挂载到各种事件,例如应用启动时的 onBootstrap,或者
00:04:15数据库记录创建时的 onRecordCreate。在拍摄时有 82 个独特的 Hook,所以几乎
00:04:21你需要的一切都已覆盖。现在让我们扩展 PocketBase 服务,看看它是如何工作的。
00:04:27如果我们查看 pb 文件夹,可以看到我们的 PocketBase 二进制文件,这个文件实际上
00:04:32就是运行默认版本 PocketBase 所需的一切。但在我的情况下,我已经编写了所有的 Hook,
00:04:38使用 TypeScript 编写的,所以我有一些设置可以将这些 Hook 编译到 pb_hooks 文件夹中作为 JavaScript,因为
00:04:44PocketBase 原生只支持 JavaScript,所以如果你使用 TypeScript,你需要将其编译。
00:04:50如果查看主要 Hook 文件,我们可以看到有一个 Hook 是 onRecordCreate,
00:04:55这专门针对我们创建问题的情况。我们在这里所做的是,
00:05:00每当记录被创建时,我们都会给用户发送一封电子邮件,我们可以通过调用
00:05:05e.app.newMailClient().send() 并传入我们在这里构建的消息对象来实现。
00:05:10你当然可以挂载到 PocketBase 内部大量的不同功能中,因此任何自定义功能
00:05:15你可能需要的,都将得到 PocketBase 中 82 个以上的 Hook 的支持。
00:05:21因为这里运行的是 SQLite,这意味着我们需要持久化存储。所以像 Heroku、Render
00:05:28或 Railway 这样的平台实际上不太合适,因为它们的文件系统是短暂的,基本上你每次重新部署应用时都会丢失数据。
00:05:33为了避免这种情况,你可以挂载一个永久文件系统。但更好且更便宜的选择
00:05:39是直接托管在 VPS 上,数据就保存在 pb_data 文件夹中。所以如果
00:05:45查看这里,你可以看到我们有一个存储文件夹,它将包含所有
00:05:50我们上传到问题中的图片。它们恰好存储在存储文件夹中,所以
00:05:55在例如这个随机 ID 文件夹里,你可以看到我之前上传到问题中的图片。
00:05:59数据库文件本身也会保存在这个文件夹中。这里的 data.db
00:06:05包含了我们所有的 SQLite 代码,所以如果我删除了这个文件,我就会丢失应用中的所有数据。
00:06:11所以很明显,你需要一个好的备份策略,而不是仅仅把它作为一个单文件留在磁盘上。
00:06:16与 Supabase 等起步价 25 美元的工具相比,PocketBase
00:06:22基本上是免费的。你只需要支付 VPS 费用,低至 4 美元即可,并且允许
00:06:28你随心所欲运行多个项目,当然随着使用量增加,你也会希望扩展它。
00:06:33PocketBase 还为你提供了生产应用所需的一切,如迁移、作业调度和
00:06:38日志记录。你也可以通过将静态文件放入 pb_public 文件夹来直接使用 PocketBase 提供服务,
00:06:44这对 React 前端等很有用。另外你也可以托管
00:06:49带有模板渲染的动态路由,这对于电子邮件模板等场景非常完美。所以如果你
00:06:54确实想要一个单盒子设置,那么这就是实现方法。现在最大的问题是:它是否已为生产准备就绪?
00:06:59它确实包含了构建现代 SaaS 应用所需的所有功能,特别是
00:07:04迁移和日志记录等生产级功能。它也是完全可扩展的,所以你不会仅仅
00:07:09受限于默认配置。但最大的坑在于它还处于 v1 版本之前,所以他们明确表示,只有在
00:07:15你能接受阅读变更日志并时不时手动执行迁移的情况下才使用它。但如果是的话,
00:07:20那么放手去做吧,你完全可以构建出第一个单文件独角兽应用。你可以通过查看
00:07:25描述中的相关链接来了解更多关于 PocketBase 的信息。如果你喜欢开源替代方案,
00:07:29那么一定要看看我们关于 OpenCode 的视频,它是 Claude Code 的开源替代品。我是 Better Stack 的 Warren,
00:07:35感谢观看,我们下次见。