十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

在 Svelte 5 中使用 RxDB:基于 runes 与 RxJS 查询订阅构建离线优先记事本应用

在 Svelte 5 中使用 RxDB:基于 runes 与 RxJS 查询订阅构建离线优先记事本应用 数据库NoSQL嵌入式数据库实时数据库【免费下载链接】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/svelte 的完整示例为主线讲解如何在 Svelte 5 应用中集成 RxDB通过$staterune 管理跨组件共享状态、在$effect内订阅 RxDB 响应式查询并自动清理订阅、使用mount()替代旧版new App()挂载组件最终实现一个具备插入、编辑、删除能力的本地优先记事本应用。读完本文你将掌握 RxDB 与 Svelte 5 响应式模型结合的标准姿势并可直接复现运行该项目。示例项目概览examples/svelte是一个使用Svelte 5runes 模式构建的快速记事本应用用于演示 RxDB 在 Svelte 生态中的集成方式。它的目录结构如下examples/svelte/ ├── public/ # 静态资源index.html、global.css、favicon ├── src/ │ ├── main.js # 入口使用 mount() 挂载组件 │ ├── App.svelte # 根组件组合 NoteList 与 NoteEditor │ ├── NoteList.svelte # $effect 中订阅 RxDB 查询 │ ├── NoteEditor.svelte # 新增/编辑笔记表单 │ ├── schema.js # RxDB 集合的 JSON schema │ └── store.svelte.js # 数据库实例 $state 共享状态 ├── test/ │ └── e2e.test.js # TestCafe 端到端测试 ├── package.json ├── rollup.config.mjs # Rollup 构建配置runes: true └── reinstall.sh项目将 RxDB 的数据库逻辑与 Svelte 的响应式状态解耦数据库初始化与查询订阅封装在store.svelte.js和NoteList.svelte中UI 组件只负责渲染与表单交互。这种分层方式同样适用于其他 Svelte 项目规模。快速启动与运行按照原文档给出的命令即可启动项目npm run preinstall npm i npm run dev随后打开 http://localhost:5000/ 即可看到应用界面。三个命令各司其职preinstall进入仓库根目录执行npx yarn1.22.22 pack把本地 RxDB 源码打包为examples/svelte/rxdb-local.tgz供当前示例引用。这是仓库 CI 环境下的特殊做法package.json中的注释也明确指出在你自己的应用中直接通过 npm 安装rxdb即可无需执行这一步npm i安装依赖。package.json中rxdb以file:rxdb-local.tgz形式声明为 devDependencynpm run dev以 watch 模式运行 Rollup同时通过serve()钩子启动静态服务器默认端口 5000。如果你不修改 RxDB 源码标准做法是npm i rxdb svelte npm run dev其他可用脚本package.json中scripts字段还提供了脚本作用npm run build执行rollup -c生成生产构建产物npm run start使用sirv public --no-clear --port 5000托管静态文件npm run test:e2e运行 TestCafe 端到端测试需设置BROWSER_PATH环境变量npm run test先构建再用concurrently同时启动服务器与 e2e 测试数据库初始化RxDB 与 Svelte 5 runes 的结合点RxDB 的初始化代码集中在 src/store.svelte.js这也是整个示例中最值得关注的部分——它演示了两件事如何创建 RxDB 数据库以及如何在 Svelte 5 中利用.svelte.js模块定义组件外共享的响应式状态。创建 RxDB 数据库import { createRxDatabase, addRxPlugin } from rxdb; import { getRxStorageLocalstorage } from rxdb/plugins/storage-localstorage; import { RxDBQueryBuilderPlugin } from rxdb/plugins/query-builder; import { wrappedValidateAjvStorage } from rxdb/plugins/validate-ajv; import { RxDBDevModePlugin } from rxdb/plugins/dev-mode; addRxPlugin(RxDBQueryBuilderPlugin); addRxPlugin(RxDBDevModePlugin); let dbPromise; const _create async () { const db await createRxDatabase({ name: rxdbdemo, storage: wrappedValidateAjvStorage({ storage: getRxStorageLocalstorage(), }) }); await db.addCollections({ notes: { schema: noteSchema } }); return db; }; export const db () dbPromise ? dbPromise : (dbPromise _create());关键点说明createRxDatabase是 RxDB 的统一入口通过name指定数据库名通过storage指定底层存储适配器。这里选用rxdb/plugins/storage-localstorage的getRxStorageLocalstorage()即把数据持久化到浏览器localStoragewrappedValidateAjvStorage来自rxdb/plugins/validate-ajv把 Ajv 校验包装成存储层使所有写入操作在进入存储前先按 schema 校验插件注册RxDBQueryBuilderPlugin提供链式查询构建能力RxDBDevModePlugin在开发模式下输出更友好的错误提示生产环境建议移除 DevMode 插件单例化db()函数用dbPromise缓存 Promise确保整个应用只初始化一次数据库。db.addCollections({ notes: { schema: noteSchema } })注册notes集合并绑定 src/schema.js 中的 schema。用 $state 承载编辑表单的共享状态Svelte 5 的 runes 机制允许在.svelte.js模块中直接使用$state从而把响应式状态提升到组件之外、供所有组件共享export const noteForm $state({ selectedNote: null, // 当前正在编辑的 RxDocument新建时为 null name: , body: }); export function selectNote(note) { noteForm.selectedNote note; noteForm.name note.name; noteForm.body note.body ?? ; } export function resetForm() { noteForm.selectedNote null; noteForm.name ; noteForm.body ; }noteForm是一个全局响应式对象任何组件读取noteForm.name或noteForm.body时都会在这些字段变化后自动重渲染selectNote()在点击列表项时把 RxDocument 加载进表单resetForm()在保存后清空表单注释明确说明Svelte 5 中共享状态放在.svelte.js模块里$staterune 可以在组件外使用。定义笔记集合的 Schemasrc/schema.js 定义了notes集合的 JSON schemaconst noteSchema { title: note, description: an individual note, version: 0, type: object, indexes: [ createdAt, updatedAt ], primaryKey: name, properties: { name: { type: string, maxLength: 100, }, body: { type: string }, createdAt: { type: number, multipleOf: 1, minimum: 0, maximum: 9999999999999 }, updatedAt: { type: number, multipleOf: 1, minimum: 0, maximum: 9999999999999 }, }, required: [name, createdAt, updatedAt], }; export default noteSchema;这个 schema 体现了 RxDB schema 的几个核心规则primaryKey: name主键必须是字符串字段这里把笔记标题设为主键。正因为主键不可变NoteEditor.svelte中编辑已存在笔记时标题输入框被设为readonlyindexes声明createdAt、updatedAt两个索引供按时间排序的查询使用。示例中列表按updatedAt倒序排列见下文 NoteList 的.sort({ updatedAt: desc })时间戳字段约束createdAt/updatedAt被限定为整数multipleOf: 1且取值范围0到9999999999999这正是以毫秒表示的 Unix 时间戳requiredname、createdAt、updatedAt为必填body可选——所以列表渲染与表单读取时都用了note.body ?? 兜底。在 $effect 中订阅 RxDB 查询NoteList.svelte演示了 RxDB 响应式查询与 Svelte 5$effect生命周期的正确配合script import { db, selectNote } from ./store.svelte.js; let noteList $state([]); let loaded $state(false); $effect(() { let subscription; let destroyed false; db().then((db$) { if (destroyed) { return; } subscription db$.notes .find() .sort({ updatedAt: desc }) .$.subscribe((notes) { noteList notes; loaded true; }); }); return () { destroyed true; if (subscription) { subscription.unsubscribe(); } }; }); const deleteNote async (note) await note.remove(); /script这里有三个值得展开的技术点$effect中订阅、cleanup 中退订$effect的回调返回一个清理函数当组件被销毁时 Svelte 会自动执行它。示例在该清理函数里标记destroyed true并调用subscription.unsubscribe()从而避免数据库异步初始化完成后对已销毁组件写入状态防止内存泄漏与在销毁组件上 set state的告警RxDB 查询的响应式入口.$db$.notes.find().sort({ updatedAt: desc })构建查询$.subscribe()订阅查询结果流。RxDB 每次有文档新增/修改/删除时都会推送最新的结果数组这正是 RxDB 响应式数据库的核心能力其实现可参考 src/rx-query.tsfind()与sort()无条件的find()返回集合全部文档.sort({ updatedAt: desc })依赖 schema 中updatedAt索引做排序配合模板中的{#each noteList as note (note.name)}渲染列表。模板部分还演示了 RxDocument 的直接操作deleteNote通过note.remove()删除文档RxDB 会立即把变更推送到所有订阅者因此删除后列表自动刷新无需手动更新noteList。插入与增量更新insert 与 incrementalPatchsrc/NoteEditor.svelte 负责新增与编辑其保存逻辑展示了 RxDB 两种写入 API 的取舍script import { db, noteForm, resetForm } from ./store.svelte.js; const saveNote async () { const db$ await db(); if (noteForm.selectedNote) { // incrementalPatch() 无需额外插件且冲突时会自动重试 await noteForm.selectedNote.incrementalPatch({ body: noteForm.body, updatedAt: new Date().getTime(), }); } else { await db$.notes.insert({ name: noteForm.name, body: noteForm.body, createdAt: new Date().getTime(), updatedAt: new Date().getTime(), }); } resetForm(); }; /script新增走insert()提供完整文档含主键name与两个时间戳字段编辑走incrementalPatch()源码注释解释了原因——incrementalPatch()不需要额外插件update()需要引入RxDBUpdatePlugin并且在检测到写冲突时会自动重试更适合多端/多标签页并发场景。它的实现位于 src/incremental-write.ts注意 RxDB 底层写入本就经过incremental-write队列串行化由于name是主键编辑时不允许修改标题所以模板里readonly{!!noteForm.selectedNote}且incrementalPatch的参数中刻意不包含name。用 mount() 启动应用src/main.js 演示了 Svelte 5 的组件挂载方式变更import { mount } from svelte; import App from ./App.svelte; /** * In Svelte 5 components are no longer classes, * they are mounted with the mount() function. */ const app mount(App, { target: document.body }); export default app;Svelte 5 中组件不再是类不能再用new App({ target })取而代之的是从svelte导入mount()函数。这是迁移到 Svelte 5 时必须注意的破坏性变更之一。根组件 src/App.svelte 只负责组合NoteList与NoteEditor两个子组件业务逻辑全部下沉到各模块。构建配置runes 模式rollup.config.mjs 中的 Svelte 编译选项显式开启了 runes 模式svelte({ compilerOptions: { // enable run-time checks when not in production dev: !production, // use the Svelte 5 runes mode, no legacy reactivity runes: true } })runes: true让编译器使用 Svelte 5 的新响应式语法$state、$effect不使用旧版基于编译的响应式构建管线还包含resolve、commonjs、css、livereload开发热更新与terser生产压缩等标准插件产物输出到public/build/bundle.js。端到端测试验证示例带有 TestCafe 编写的 e2e 测试 test/e2e.test.js覆盖了两条核心用户路径可作为RxDB Svelte 集成正确性的可执行验证新增笔记清空已有笔记 → 输入标题与正文 → 点击 Save Note → 断言列表中出现了对应条目编辑已有笔记插入一条笔记后断言表单被重置 → 点击列表项把文档载入表单 → 修改正文保存 → 断言列表仍只有一条说明是更新而非重复插入且正文已更新为second version。测试还验证了响应式行为保存后输入框被清空resetForm()生效、列表自动出现新条目RxDB 查询流推送生效。运行测试脚本为npm run test需在支持 TestCafe 的浏览器环境下执行仓库 CI 通过BROWSER_PATH指定浏览器路径。小结把这套模式移植到自己的 Svelte 项目本示例的可复用要点可以概括为四条数据库单例在.svelte.js模块中用闭包缓存createRxDatabase的 Promise通过db()延迟初始化并全局复用状态分层RxDB 负责数据持久化与变更推送Svelte 的$state只承载表单正在编辑什么这类 UI 状态二者通过selectNote/resetForm这类纯函数衔接订阅生命周期所有 RxDB 查询订阅都放进$effect并在 cleanup 中unsubscribe()杜绝内存泄漏写入策略主键不可变更新优先使用自带冲突重试的incrementalPatch()而不是需要额外插件的update()。在此基础上你可以把getRxStorageLocalstorage()替换为 RxDB 的其他存储适配器如 IndexedDB、SQLite、Memory接入复制协议replication实现多端同步进一步发挥 RxDB 离线优先的完整能力。赞分享数据库NoSQL嵌入式数据库实时数据库【免费下载链接】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点击查看免费下载相关推荐React 应用中使用 IndexedDB用 RxDB 实现响应式查询与离线优先React 应用中使用 IndexedDB用 RxDB 实现响应式查询与离线优先 IndexedDB 是浏览器内置的结构化数据存储方案但原生 API 的回调数据库NoSQL嵌入式数据库实时数据库使用 TanStack DB 与 RxDB 构建离线优先Offline-First应用使用 TanStack DB 与 RxDB 构建离线优先Offline First应用 TanStack DB 是内存态响应式客户端存储提供实时查询li数据库NoSQL嵌入式数据库实时数据库TanStack DB 在 Electron 中的本地数据库基于 RxDB SQLite 存储构建离线优先桌面应用TanStack DB 在 Electron 中的本地数据库基于 RxDB SQLite 存储构建离线优先桌面应用 TanStack DB in Electr数据库NoSQL嵌入式数据库实时数据库创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表