当前位置: 首页 > article >正文

本地优先 Web 应用开发:React/SQLite 前端、Supabase 后端与 PowerSync 同步引擎实践

本地优先 Web 应用开发React/SQLite 前端、Supabase 后端与 PowerSync 同步引擎的实践与优势并非每天都会出现全新架构如今浏览器内的 SQLite 结合响应式 SQL 和自动同步功能出现了它能让前端即时交互还能保持与后端数据一致作为 RESTful 思维模式的挑战者值得深入探究。并非全新而是改进这个想法并非全新概念多年来开发者一直以各种方式做类似事情如某些应用的离线功能。但这新一代技术栈有所不同开始受广泛关注它叫本地优先数据。此前已宏观介绍该概念现在深入探究细节。其概念简单应用无需向远程服务器请求更改数据权限而是直接将状态写入浏览器中运行的本地 SQLite 数据库通过 WebAssembly然后复杂的后台引擎会将更改同步到云端和其他设备。对 React 开发者来说仍处于响应式范式即便编写原始 SQL 查询数据处理也会自动完成。UI 组件会订阅数据库数据变化时不管是用户本地点击还是云端同步更新UI 会立即更新。就像用 Spotify 时不用下载数百万首歌曲完整目录只下载自己歌单离线也能无延迟收听音乐。用本地优先数据构建的模式类似但功能更强大。可对本地状态进行更改有网络连接时更改会同步到后端也会自动接收外界重要更新。三个架构组件要实现这一点需要三个主要架构组件客户端 UI 和数据库React 和 SQLite Wasm同步引擎PowerSync记录数据库Supabase先设置所需云服务Supabase 和 PowerSync两者都有免费套餐。对于客户端 UI 和数据库使用 Supabase 提供的 React SQLite 演示应用。Supabase记录数据库Supabase 是托管的 Postgres 服务有很多实用功能。示例很简单只需一行数据。访问 Supabase.com创建免费账户然后启动新项目点击项目可查看详细信息。接着创建数据库模式存储数据这是简单模式。在左侧菜单中打开 SQL 编辑器并运行以下代码-- 1. 创建表来存储计数器 CREATE TABLE counters ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), created_at TIMESTAMPTZ DEFAULT NOW(), count INTEGER DEFAULT 0, owner_id UUID DEFAULT auth.uid() ); -- 2. 开启行级安全RLS ALTER TABLE counters ENABLE ROW LEVEL SECURITY; -- 3. 访问策略 CREATE POLICY Users can all on own counters ON counters FOR ALL USING (auth.uid() owner_id); -- 4. 发布表 DROP PUBLICATION IF EXISTS powersync; CREATE PUBLICATION powersync FOR TABLE counters;以上代码各步骤有注释。第一步是标准 SQL 操作创建含几列的表包括随机 UUID 主键。第二步开启行级安全。第三步创建访问策略允许用户访问自己的计数器行由登录 ID 确定auth.uid() owner_id。第四步在 Supabase 实例和 PowerSync 之间建立连接。离开 Supabase 前点击顶部“ Connect”按钮获取连接字符串格式类似postgresql://postgres:[YOUR-PASSWORD]db.fooizpddffaabqcydusj.supabase.co:5432/postgresPowerSync同步引擎进入 PowerSync访问 PowerSync.com创建免费账户然后启动新项目打开项目详细信息。在 PowerSync 仪表板中创建与 Supabase 的连接按以下步骤操作点击“Create New Instance”。点击左侧“Database Connections”然后点击“”按钮。粘贴从 Supabase 复制的连接字符串。注意若字符串中有 [YOUR-PASSWORD] 占位符将其替换为为实例创建的实际密码。点击“Test Connection”。PowerSync 会连接到之前创建的 Postgres 实例。若在 Supabase 设置中正确运行 CREATE PUBLICATION SQL 命令这一步将成功会看到绿色“Connection Successful!”状态消息。配置身份验证已告诉 PowerSync 如何读取 Supabase 数据Postgres现在要告诉它如何信任用户步骤如下在 PowerSync 仪表板中点击“Client Auth”选项卡。找到“JWKS URI”字段。构建 JWKS URL它是 Supabase 项目 URL 加特定后缀格式为https://[YOUR-PROJECT-ID].supabase.co/auth/v1/.well-known/jwks.json。注意可从 Supabase Settings API 获取项目 URL。将 JWKS URL 粘贴到“JWKS URI”字段中然后点击“Save”。将“Audience”设置为“authenticated”点击“Token Claims”下的“() Add”按钮。“Claim”类型选择“aud”“Value”类型选择“authenticated”。此配置告诉 PowerSync“只信任由 Supabase 签名且针对‘authenticated’用户组的令牌。”定义同步规则同步规则是理解架构的关键要素在这里告诉 PowerSync 用户可访问哪些数据这有时也叫用户的数据“形状”。每个用户根据独特配置文件对整体数据有不同“形状”。不想将整个数据库同步到用户笔记本电脑上这在很多方面不可行。相反定义一个同步规则在 PowerSync 中称为“bucket”它是过滤器用于确定哪些数据属于哪个用户。导航到左侧“Sync Rules”会看到 YAML 编辑器将默认代码替换为以下代码edition: 2 bucket_definitions: user_counters: # 1. 从身份验证令牌中识别用户 parameters: SELECT request.user_id() as user_id # 2. 仅同步属于他们的行 data: - SELECT * FROM counters WHERE owner_id bucket.user_id这段代码为用户定义了数据的特殊视图user_counters这是“bucket”即一组数据。request.user_id()PowerSync 会自动从 Supabase 身份验证令牌中提取用户 ID。数据查询此 SQL 在云端运行仅获取 owner_id 列与登录用户匹配的行并将其流式传输到设备。可点击“Validate”检查是否正常工作点击“Deploy”使其生效。React 和 SQLite客户端 UI 和数据库已完成大量管理工作这为构建了基于 SQL 的完整响应式架构。继续开发可使用该架构的客户端为快速了解从 Supabase 克隆演示应用。在命令行中运行$ git clone https://github.com/powersync-community/vite-react-ts-powersync-supabase.git $ cd vite-react-ts-powersync-supabase $ npm installnpm 命令完成后需将应用指向刚刚创建的基础设施可使用 .env.local 环境变量文件实现。打开 .env.local将变量更改为指向服务代码如下VITE_SUPABASE_URLhttps://fooizpddffaabqcydusj.supabase.co VITE_SUPABASE_ANON_KEYsb_publishable_gqUrYxDt04rg74fopz5rUg_ayDxpmgE VITE_POWERSYNC_URLhttps://foofcf18cc2560584a018a12.powersync.journeyapps.com现在可测试 React 应用$ npm run dev:ui演示应用是简单计数器即显示“Increment”按钮并显示计数的网页。虽看起来不特别令人兴奋但背后的数据同步功能很神奇。运行上述命令后会打开浏览器窗口显示“Create Counter”按钮。点击它演示应用会在新窗口中创建计数器同时显示用户 ID 和显示连接和同步状态的面板。可根据需要创建任意数量的计数器每个计数器都在单独的浏览器窗口中。可通过访问 Supabase 仪表板查看“Table”面板确认计数器表中确实为用户插入了一行数据以此验证计数器是否正常工作。另一个好方法是用另一个浏览器/设备或隐身标签登录在第二个浏览器窗口中创建另一个计数器这样可同时看到两个由 Supabase 同步的会话计数器。React 代码App.tsx进展很快但 src/App.tsx 文件中有值得注意的有趣内容。这段代码是应用的主要 React 代码展示了从“向服务器请求数据”到“与本地数据库状态交互”的转变。每个 React 开发者都需关注两个关键部分响应式读取和即时写入。响应式读取useQuery在标准 React 应用中会使用 useEffect 调用 fetch(/api/counters) 来获取数据。在本地优先 React 应用中使用原始 SQLconst { data: counters, isLoading } useQuery( SELECT * FROM ${COUNTER_TABLE} ORDER BY created_at ASC, [], { rowComparator: { keyBy: (item) item.id, compareBy: (item) JSON.stringify(item) } } );这是架构中的“响应式 SQL”部分。useQuery 钩子会订阅本地 SQLite 数据库。当后台工作进程从云端接收到更新或者在本地更新一行数据时这个钩子会立即触发并重新渲染组件。无需手动管理状态或重新获取数据的逻辑也没有中间状态对象。后端状态和前端状态是一致的。即时写入powerSync.execute注意增加计数器时的情况。没有 await api.post(...)也没有加载状态。const updateCounter async (counter: CounterRecord, newCount: number) { // 立即写入本地 SQLite await powerSync.execute( UPDATE ${COUNTER_TABLE} SET count ? WHERE owner_id ?, [newCount, counter.owner_id] ); };这段代码本身很有趣因为它像响应式 SQL 语句。将数据写入本地文件Wasm写入操作在毫秒内完成UI 会通过 useQuery 钩子立即更新。PowerSync 同步引擎会异步捕获更改并将其推送到 Supabase。本地优先与 RESTful 的比较那么所有这些配置和新颖的代码是否值得呢如果构建简单的仪表盘或基于表单的应用程序传统的 JSON APIREST 或 GraphQL方法仍是首选。在这些模型中服务器是唯一的数据源客户端只是简单的终端。它简单、无状态且易于调试也很常见。但这种简单性不可避免地带来了延迟成本。每次交互都需要与服务器进行往返通信。如果网络出现问题应用程序就会冻结。JSON API 要求手动管理加载状态、错误边界和乐观 UI 回滚。本地优先则改变了这种情况。需要在前期付出更高的成本需要定义模式、管理本地数据库并考虑同步规则。但作为回报将获得感觉像原生软件的应用程序。本地优先实现了数据的连续性即使离开 Wi-Fi 范围也能继续工作重新连接后数据会在不同设备间同步。从架构上看使用了三个主要组件数据库、同步引擎和客户端。这实际上与传统的 RESTful 栈类似。在本地优先架构中同步引擎取代了 JSON API 服务器的角色。简而言之整体复杂度相似但具体实现有所不同。本地优先架构对于 JavaScript 和 Web 开发来说是一个令人着迷的发展方向。虽然要克服 JSON API 的巨大惯性并不容易但这确实是一股新的潮流。本地优先可能永远无法达到 RESTful 架构的普及程度但本地优先数据和响应式 SQL 是目前值得密切关注的重要趋势之一。关键词Web 开发、开发方法、软件开发、库和框架

相关文章:

本地优先 Web 应用开发:React/SQLite 前端、Supabase 后端与 PowerSync 同步引擎实践

本地优先 Web 应用开发:React/SQLite 前端、Supabase 后端与 PowerSync 同步引擎的实践与优势并非每天都会出现全新架构,如今浏览器内的 SQLite 结合响应式 SQL 和自动同步功能出现了,它能让前端即时交互,还能保持与后端数据一致&…...

结构函数:电子封装热分析的关键技术解析

1. 结构函数:热分析领域的核心桥梁在电子封装设计与散热方案开发中,热特性分析一直是个令人头疼的问题。想象一下,你手里拿着一块正在发烫的芯片,却无法直接"看到"热量是如何在内部传递的——这就像医生无法用X光检查病…...

Next.js App Router 实战:从官方 Playground 探索现代 Web 开发最佳实践

1. 项目概述与定位最近在捣鼓 Next.js 的几个新特性,比如 Server Actions、并行路由、拦截路由这些,光看文档总觉得隔靴搔痒,想找个能上手实操、快速验证想法的环境。这时候,Vercel 官方维护的next-app-router-playground项目就成…...

CAPL脚本中数据类型转换的实战解析:ASCII数组与字符串的精准互转

1. 为什么需要ASCII数组与字符串互转 在汽车电子测试领域,我们经常需要处理各种数据格式的转换。比如ECU返回的报文可能是以ASCII数组形式呈现的,而我们需要将其转换为可读的字符串进行分析;反过来,当我们需要发送特定指令时&…...

repo2txt:从Git仓库到结构化文本的自动化提取工具详解

1. 项目概述:从代码仓库到纯文本的自动化提取最近在整理个人技术笔记和搭建内部知识库时,我遇到了一个挺普遍但有点烦人的问题:如何把分散在多个Git仓库里的代码、文档和配置文件,快速、完整地转换成结构清晰的纯文本文件&#xf…...

GitHub Explorer:基于OpenClaw的AI Agent自动化项目分析工具

1. 项目概述:一个为AI Agent打造的GitHub项目深度分析工具 如果你和我一样,经常需要快速评估一个GitHub项目的价值、技术栈、社区活跃度以及它在整个生态中的位置,那你一定知道这个过程有多繁琐。你得手动点开仓库,看README&…...

LLM长文本处理实战:模块化分割策略与向量化预处理指南

1. 项目概述:一个为LLM打造的文本处理中心如果你和我一样,经常和大型语言模型打交道,无论是用它来总结文档、分析代码,还是处理客服对话,那你肯定遇到过这个痛点:喂给模型的文本太长了怎么办?模…...

Agent Skill Exchange:标准化AI技能库,赋能智能编程助手

1. 项目概述:Agent Skill Exchange 是什么,以及它为何重要 如果你最近在折腾 Claude Code、Cursor 或者 Codex 这类 AI 编程助手,可能会发现一个痛点:虽然它们很强大,但要让它们真正理解并调用你项目里特定的工具链、…...

如何一次性解决Windows系统DLL缺失问题:VisualCppRedist AIO终极指南

如何一次性解决Windows系统DLL缺失问题:VisualCppRedist AIO终极指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾经在安装新游戏或软件时…...

鸣潮帧率解锁终极指南:用WaveTools轻松突破120FPS限制

鸣潮帧率解锁终极指南:用WaveTools轻松突破120FPS限制 【免费下载链接】WaveTools 🧰鸣潮工具箱 项目地址: https://gitcode.com/gh_mirrors/wa/WaveTools 还在为鸣潮游戏中被锁定的60FPS帧率而烦恼吗?想让你的高刷新率显示器发挥真正…...

一键部署Obsidian环境:自动化脚本实现跨设备配置同步

1. 项目概述:为什么我们需要一个“一键式”的 Obsidian 安装脚本?如果你是一个深度依赖 Obsidian 进行知识管理、笔记写作或项目规划的从业者,无论是程序员、作家、学生还是研究员,大概率都经历过这样的场景:换了一台新…...

基于agent-foundry框架构建智能体:从核心原理到天气助手实战

1. 项目概述:从零构建你的智能体开发框架最近在GitHub上看到一个挺有意思的项目,叫hebertzhu/agent-foundry。乍一看名字,你可能会觉得这又是一个跟风大语言模型热潮的“又一个Agent框架”。但当我真正深入去研究它的代码结构、设计理念和实际…...

AI辅助开发工作流:用免费代理优化付费工具,提升代码生成效率

1. 项目概述:用免费AI代理优化付费AI工具的开发工作流如果你和我一样,订阅了Claude Pro或者GitHub Copilot,但每个月看着额度条飞速见底,心里总有点发慌,那这篇文章就是为你准备的。我们不是在讨论哪个AI写代码更强&am…...

告别生产翻车!用Altium Designer 21的DRC规则为你的PCB设计上好“保险”

Altium Designer 21 DRC规则深度实战:从设计规范到生产就绪的PCB 在硬件开发领域,PCB设计完成后到实际生产前的最后一道防线就是设计规则检查(DRC)。很多工程师将DRC视为简单的软件功能验证,但实际上,它承担…...

vibe-to-ui:让AI助手将你的“感觉”翻译成专业设计系统

1. 项目概述:当“感觉”成为设计语言如果你和我一样,是一个能写出复杂业务逻辑,但一碰到UI设计就头疼的开发者,那今天聊的这个工具,可能会彻底改变你的工作流。我们常常陷入一个困境:心里有一个模糊的“感觉…...

从零构建ESP32+ILI9341触摸屏LVGL交互界面实战

1. 硬件选型与连接指南 第一次接触ESP32和ILI9341触摸屏时,最让我头疼的就是如何正确选择硬件并完成连接。经过多次实践,我总结出一套适合新手的硬件配置方案。ESP32开发板建议选择带有USB转串口芯片的版本,比如ESP32-DevKitC,这样…...

泰拉瑞亚地图编辑器TEdit:5步打造专业级游戏世界的终极指南

泰拉瑞亚地图编辑器TEdit:5步打造专业级游戏世界的终极指南 【免费下载链接】Terraria-Map-Editor TEdit - Terraria Map Editor - TEdit is a stand alone, open source map editor for Terraria. It lets you edit maps just like (almost) paint! It also lets y…...

5分钟快速上手:XUnity.AutoTranslator游戏翻译插件完整教程

5分钟快速上手:XUnity.AutoTranslator游戏翻译插件完整教程 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator 还在为外语游戏的语言障碍而烦恼吗?XUnity.AutoTranslator是一款强大的…...

Windows平台APK部署技术探索:轻量级安卓应用安装实践指南

Windows平台APK部署技术探索:轻量级安卓应用安装实践指南 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 在跨平台应用开发与部署日益普及的今天&#xff0…...

不止是画框!深入理解Cadence Allegro中Route Keepout与Route Keepin的实战区别

不止是画框!深入理解Cadence Allegro中Route Keepout与Route Keepin的实战区别 在PCB设计领域,约束管理系统的精准运用往往决定着设计成败。对于使用Cadence Allegro的工程师而言,Route Keepout(禁止布线区)和Route Ke…...

5个场景告诉你:为什么你需要这款免费的窗口分辨率神器

5个场景告诉你:为什么你需要这款免费的窗口分辨率神器 【免费下载链接】SRWE Simple Runtime Window Editor 项目地址: https://gitcode.com/gh_mirrors/sr/SRWE 你是否曾遇到过这些困扰?游戏内分辨率选项有限,无法满足你对极致画质的…...

在Windows上直接安装Android应用的革命性方案:APK安装器完全指南

在Windows上直接安装Android应用的革命性方案:APK安装器完全指南 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否曾经希望在Windows电脑上直接运行手…...

【统计推断实战】从置信区间到假设检验:如何用数据做出可靠决策

1. 从产品迭代案例看统计推断的价值 最近团队上线了一个新功能,产品经理信心满满地宣称能提升15%的用户留存率。但上线一周后数据波动很大,有人觉得效果明显,有人却说毫无变化。这时候该信谁的?其实这就是统计推断大显身手的时刻—…...

如何免费实现iOS设备虚拟定位?iFakeLocation跨平台实用指南

如何免费实现iOS设备虚拟定位?iFakeLocation跨平台实用指南 【免费下载链接】iFakeLocation Simulate locations on iOS devices on Windows, Mac and Ubuntu. 项目地址: https://gitcode.com/gh_mirrors/if/iFakeLocation 你是否曾经想过,在舒适…...

Windows系统优化神器:3步解决C盘爆红和电脑卡顿难题

Windows系统优化神器:3步解决C盘爆红和电脑卡顿难题 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服! 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 你是否曾经遇到过Windows电脑C盘空间不足的困扰&a…...

React Native Expo样板项目:集成导航、状态管理与样式的最佳实践

1. 项目概述:一个为React Native开发者准备的“开箱即用”脚手架 如果你是一名React Native开发者,或者正打算踏入这个领域,那么你一定对项目启动初期那些繁琐的配置工作深有体会。从搭建开发环境、配置路由、集成状态管理,到设置…...

Bootstrap 标签页

Bootstrap 标签页 Bootstrap 标签页(Tab)是 Bootstrap 框架中的一种交互组件,允许用户在多个页面元素或内容区域之间进行切换。本文将详细介绍 Bootstrap 标签页的使用方法、特点以及如何将其应用于实际项目中。 一、Bootstrap 标签页的使用方…...

从‘坍缩’到‘对齐’:用SimCSE解决BERT句子向量老难题,我的中文业务实验复盘

从语义坍缩到精准对齐:SimCSE在中文业务场景的实战指南 BERT模型在自然语言处理领域取得了巨大成功,但其原生句子向量存在一个令人头疼的问题——语义坍缩。简单来说,就是不同句子的向量在高维空间中倾向于聚集在一起,导致相似度计…...

OpenClaw-Zulip桥接器:实现AI Agent与团队协作工具的无缝集成

1. 项目概述:一个为AI Agent打造的Zulip消息桥梁如果你正在构建一个基于OpenClaw的AI Agent系统,并且你的团队恰好使用Zulip作为内部沟通工具,那么你很可能面临一个痛点:如何让Agent无缝地融入团队的日常对话流?是让团…...

AI辅助开发实战:用Electron+React+TS构建跳台滑雪模拟器

1. 项目概述:一个由AI驱动的滑雪跳台模拟器如果你是一个体育游戏迷,尤其是对冬季项目里的跳台滑雪着迷,同时又对现代前端开发技术栈感兴趣,那么这个名为Sj.Sim Predazzo Edition的开源项目,绝对值得你花时间深入研究。…...