尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

在 Tauri 2 桌面应用中集成 RxDB:基于 SQLite RxStorage 的本地优先数据库实战

在 Tauri 2 桌面应用中集成 RxDB:基于 SQLite RxStorage 的本地优先数据库实战 在 Tauri 2 桌面应用中集成 RxDB基于 SQLite RxStorage 的本地优先数据库实战【免费下载链接】rxdbThe local-first database that runs on every JS runtime and replicates with your existing backend - no vendor, no lock-in - https://rxdb.info/项目地址: https://gitcode.com/gh_mirrors/rx/rxdb本篇技术指南以 examples/tauri 示例项目为主线完整讲解如何在一个 Tauri 2 桌面应用中接入 RxDB并通过 SQLite RxStorage 将数据库落盘到系统本地 SQLite。你将在本指南中掌握Tauri 项目的环境准备与启动流程、Rust 侧 SQL 插件与自定义命令的注册方式、RxDB 数据库与集合的初始化模式以及如何借助响应式查询实现界面数据自动刷新。一、示例概览一个英雄列表桌面应用该示例实现了一个简单的英雄列表heroes-list应用用户可以在界面中输入英雄的名字name与颜色color数据被持久化到本地 SQLite 数据库中并实时反映在列表 UI 上。整体技术栈为Tauri 2 桌面框架前端基于 Vite 原生 HTML/JS后端基于 RustSQLite RxStorageRxDB 的 SQLite 存储层Tauri SQL 插件Rust 与前端之间的 SQLite 桥接从仓库结构看示例包含完整的工程骨架index.html应用唯一页面包含英雄列表容器#heroes-list与添加英雄的表单src/main.js前端入口负责创建 RxDB 实例、订阅查询并绑定插入逻辑src/database.jsRxDB 数据库与集合的创建封装src-tauriRust 侧工程含 lib.rs、tauri.conf.json 与权限声明 capabilities/default.jsontest/specs/example.e2e.js基于 WebdriverIO 的端到端测试二、环境准备与启动步骤2.1 前置依赖运行该示例前需要准备Node.js 与 npm/yarn 环境用于前端构建与 RxDB 安装Rust 工具链用于编译 Tauri 的 Rust 后端示例依赖 tauri 2、tauri-plugin-sql 等 crate见 Cargo.tomlTauri CLI项目已将其声明为 devDependency见 package.json系统级的 Tauri 编译依赖不同操作系统所需的 WebKitGTK / WebView2 等属于 Tauri 官方要求。2.2 启动步骤官方 README 给出的完整步骤如下对应 examples/tauri/README.md克隆整个 RxDB 仓库本仓库即为该仓库的镜像进入项目根目录并安装依赖cd rxdb npm install进入示例目录cd examples/tauri安装本地化依赖npm run preinstall npm install -D启动开发模式npm run tauri dev。其中preinstall脚本会在安装前执行preinstall:rxdb其实现是preinstall:rxdb: (cd ../../ npx yarn1.22.22 pack ../../ --filename ./examples/tauri/rxdb-local.tgz)这段命令将仓库根目录的 RxDB 源码打包成本地 tarballrxdb-local.tgz随后package.json中的rxdb: file:rxdb-local.tgz会基于这份本地源码包安装 RxDB。这样做保证了示例始终与仓库中的 RxDB 源码保持同步而不是使用 npm 上可能滞后的发布版本。提示仓库中还提供了 reinstall.sh它会清除node_modules与rxdb-local.tgz然后重新执行 preinstall 与依赖安装适合在 RxDB 源码更新后一键重建本地环境。2.3 Vite 与 Tauri 的端口约定examples/tauri/vite.config.js 为 Tauri 开发做了针对性配置clearScreen: false避免 Vite 清屏掩盖 Rust 编译错误server.port: 1420, strictPort: trueTauri 期望固定端口 1420端口被占用时直接报错而非换端口hmr.port: 1421热更新走 WebSocket 端口 1421仅在设置了TAURI_DEV_HOST时启用 HMRserver.watch.ignored: [**/src-tauri/**]告诉 Vite 忽略对src-tauri目录的监听避免 Rust 文件的变动触发前端不必要的重载。与之对应tauri.conf.json 的build段声明了build: { beforeDevCommand: npm run dev, devUrl: http://localhost:1420, beforeBuildCommand: npm run build, frontendDist: ../dist }即开发模式先启动 Vite 开发服务器端口 1420再拉起 Tauri 窗口构建模式则先执行npm run buildtsc vite build产物输出到../dist供 Rust 侧打包。三、Rust 侧SQL 插件与自定义命令3.1 注册 SQL 插件Tauri 应用需要在 Rust 侧注册 SQL 插件前端才能通过tauri-apps/plugin-sql访问 SQLite。见 src-tauri/src/lib.rspub fn run() { tauri::Builder::default() .plugin(tauri_plugin_sql::Builder::new().build()) .plugin(tauri_plugin_opener::init()) .invoke_handler(tauri::generate_handler![get_db_suffix]) .run(tauri::generate_context!()) .expect(error while running tauri application); }同时 Cargo.toml 中开启了 SQLite 特性tauri-plugin-sql { version 2, features [sqlite] }3.2 自定义 Rust 命令生成数据库后缀为了让每次运行都能获得独立、全新的数据库实例示例在 Rust 侧定义了一个命令get_db_suffix返回当前时间的毫秒时间戳#[tauri::command] fn get_db_suffix() - String { let start SystemTime::now(); let since_the_epoch start .duration_since(UNIX_EPOCH) .expect(Time went backwards); format!({}, since_the_epoch.as_millis()) }前端通过invoke(get_db_suffix, {})调用该命令见 src/main.js并将返回值拼接到数据库名heroesdb dbSuffix上。这样每次启动都会创建带时间戳后缀的新数据库避免了旧数据的干扰这一设计也体现在端到端测试的多次运行场景中。3.3 权限声明CapabilitiesTauri 2 引入了基于 capability 的权限模型。capabilities/default.json 为main窗口声明了permissions: [ core:default, opener:default, sql:default, sql:allow-execute ]其中sql:default与sql:allow-execute允许前端通过 SQL 插件执行 SQL 语句。缺少这些权限时前端调用 SQL 插件会被 Tauri 安全层拒绝。四、前端初始化 RxDB 与 SQLite RxStorage4.1 创建 RxDB 实例examples/tauri/src/database.js 封装了数据库与集合的创建import { createRxDatabase, addRxPlugin } from rxdb; import { RxDBQueryBuilderPlugin } from rxdb/plugins/query-builder; import { RxDBDevModePlugin } from rxdb/plugins/dev-mode; addRxPlugin(RxDBQueryBuilderPlugin); addRxPlugin(RxDBDevModePlugin); const heroSchema { title: hero schema, description: describes a simple hero, version: 0, primaryKey: name, type: object, properties: { name: { type: string, maxLength: 100 }, color: { type: string }, }, required: [name, color], }; export async function getDatabase(name, storage) { const db await createRxDatabase({ name, storage }); await db.addCollections({ heroes: { schema: heroSchema } }); return db; }这里有两个值得注意的设计点getDatabase(name, storage)将存储层作为参数注入使得数据库创建逻辑与具体存储实现解耦测试时可轻松替换为内存存储等实现注册了RxDBQueryBuilderPlugin与RxDBDevModePlugin前者提供链式查询构建器能力后者在开发阶段对 schema、查询等进行运行时校验该插件不应在生产环境使用它只应在开发模式启用。4.2 SQLite RxStorage 的接入真正的关键在 src/main.jsimport { invoke } from tauri-apps/api/core; import sqlite3 from tauri-apps/plugin-sql; import { getRxStorageSQLiteTrial, getSQLiteBasicsTauri, } from rxdb/plugins/storage-sqlite; import { wrappedValidateAjvStorage } from rxdb/plugins/validate-ajv; const dbSuffix await invoke(get_db_suffix, {}); const storage getRxStorageSQLiteTrial({ sqliteBasics: getSQLiteBasicsTauri(sqlite3), }); const db await getDatabase( heroesdb dbSuffix, wrappedValidateAjvStorage({ storage: storage }), );接入链路分为三步getSQLiteBasicsTauri(sqlite3)将 Tauri SQL 插件封装为 RxDB SQLite 存储所需的SQLite 基础能力连接、查询、事务等getRxStorageSQLiteTrial({ sqliteBasics })基于上述能力构造 RxDB 的 SQLite 存储实例wrappedValidateAjvStorage({ storage })在其外层叠加 AJV 文档校验确保写入数据符合 heroSchema 定义。其中getRxStorageSQLiteTrial名称中的 Trial 表明这是 SQLite RxStorage 的试用版实现正式使用时应参考 SQLite RxStorage 文档 选择合适的变体例如非试用版或带加密的版本。命名还揭示了 RxDB 存储层的分层思想RxStorage 与数据校验是正交的两层可以任意组合。五、响应式查询让 UI 自动跟随数据变化5.1 订阅查询结果示例最核心的 RxDB 能力展示是对查询结果的订阅src/main.jsdb.heroes .find() .sort({ name: asc }) .$.subscribe(function (heroes) { if (!heroes) { heroesList.innerHTML Loading..; return; } heroesList.innerHTML heroes .map((hero) { return ( li div classcolor-box stylebackground: hero.color /div div classname name hero.name hero.name /div /li ); }) .reduce((pre, cur) (pre cur), ); });db.heroes.find().sort({ name: asc }).$是一个可观察的Observable查询流当集合内数据发生任何增删改时RxDB 会重新执行查询并向订阅者推送最新结果前端无需手动管理数据刷新。这正是 RxDB 响应式特性的典型用法——数据层变化自动驱动 UI 渲染。5.2 插入数据表单提交通过全局函数addHero完成src/main.jswindow.addHero async function () { const name document.querySelector(input[namename]).value; const color document.querySelector(input[namecolor]).value; const obj { name: name, color: color }; await db.heroes.insert(obj); };页面中的按钮通过onclickaddHero();绑定见 index.html。由于 schema 要求name与color均为必填字段且name是主键重复插入同名英雄会被主键冲突规则拦截开发模式下 DevMode 插件还会给出更详细的校验提示。六、端到端测试验证应用行为6.1 运行测试README 指出运行测试前必须安装 Tauri Driver 及相关系统依赖tauri-driver是 Tauri 官方的 WebDriver 实现用于驱动真实窗口执行自动化测试。测试脚本定义在 package.jsontest: npm run tauri build -- --no-bundle wdio run wdio.conf.cjs即先构建 release 版可执行文件不打包安装包再以 WebdriverIO 执行测试。6.2 测试配置解析wdio.conf.cjs 的核心配置capabilities: [ { maxInstances: 1, tauri:options: { application: ./src-tauri/target/release/tauri, }, }, ], beforeSession: () (tauriDriver spawn( path.resolve(os.homedir(), .cargo, bin, tauri-driver), [], { stdio: [null, process.stdout, process.stderr] } )), afterSession: () tauriDriver.kill(),它在每个测试会话开始前自动拉起tauri-driver进程会话结束后将其终止被测应用指向 release 构建产物./src-tauri/target/release/tauri。6.3 测试用例test/specs/example.e2e.js 包含两个用例页面加载成功断言页面标题文本为RxDB Heroes Tauri插入英雄通过输入框#input-name、#input-color填写Iron Man/red并点击#input-submit然后等待列表中只出现一个名为Iron Man的元素waitForExist超时 20 秒并断言元素数量为 1。第二个用例同时验证了完整链路前端插入 → RxDB 写入 SQLite → 响应式订阅触发 → DOM 更新出现新条目。由于每次运行都使用新的时间戳后缀数据库测试的多次执行之间不会互相污染。七、小结该示例揭示的 RxDB 桌面端最佳实践存储层与逻辑层分离getDatabase(name, storage)接受注入的 storage使数据库代码可复用、可测试适配器模式RxDB 通过getSQLiteBasicsTauri将 Tauri SQL 插件适配为统一的 SQLite 存储接口因此同一套 RxDB API 可横跨浏览器、Node.js、Electron、Tauri 等不同运行时响应式驱动 UI查询订阅流.$.subscribe让数据变更自动映射到界面这是构建本地优先local-first应用的基石开发/生产分离DevMode 插件仅用于开发期校验生产构建不应包含。若想在此基础上扩展可以结合仓库中的 SQLite RxStorage 文档 了解其实现细节与更多配置选项或在 examples/electron、examples/vite-vanilla-ts 等示例中对比 RxDB 在其他桌面/前端场景下的接入方式。【免费下载链接】rxdbThe local-first database that runs on every JS runtime and replicates with your existing backend - no vendor, no lock-in - https://rxdb.info/项目地址: https://gitcode.com/gh_mirrors/rx/rxdb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表