文章摘要
Marco是一款跨平台的电子邮件管理应用,支持IMAP协议,并强调离线优先的设计理念。用户可以在无网络连接时阅读、删除、回复和组织邮件,重新连接后自动同步。与简单的待办应用不同,Marco处理大量数据,涉及数百MB和数十万甚至数百万条记录,因此其离线功能的实现复杂度远超预期。
文章总结
离线优先的挑战与解决方案:Marco的探索之旅
在开发Marco这款跨平台的电子邮件管理应用时,我们面临了两大核心挑战:基于IMAP协议而非API,以及支持多平台(包括Web、Mac、Windows、Android和iOS)。此外,我们还设定了离线优先的架构目标,但很快发现这一目标的复杂性远超预期。
Marco的设计理念是,用户在没有网络连接的情况下,仍能阅读、删除、回复和组织邮件,并在重新连接网络后自动同步所有操作。然而,Marco并非简单的待办事项应用,它需要处理数百MB的数据和数十万甚至数百万条记录,这使得我们直接进入了离线优先实现中最复杂的1%用例。
初探:WatermelonDB
在2024年8月,我们深入研究了多种离线优先解决方案,最终选择了WatermelonDB。WatermelonDB是一个开源、自托管的数据库无关解决方案,尽管它在许多生产应用中表现良好,但我们很快发现了其局限性。特别是在Web端,WatermelonDB依赖IndexedDB,而IndexedDB的性能问题导致我们不得不使用LokiJS作为内存数据库来缓解性能瓶颈。然而,随着数据量的增加,内存占用和同步问题逐渐显现,最终我们不得不重新评估这一选择。
新一代离线优先解决方案
在意识到WatermelonDB无法满足我们的需求后,我们开始探索新一代的离线优先解决方案,包括Triplit、InstantDB和Convex。尽管Triplit在开发者体验上表现出色,但其服务器端的内存占用和客户端的性能问题让我们无法将其应用于Marco。InstantDB虽然在功能上与Triplit类似,但其缺乏类型支持、排序功能和后端Webhooks,使得它同样不适合我们的需求。
PowerSync的失望
最终,我们尝试了PowerSync,尽管它在技术上最为成熟,但其复杂的自托管要求、高昂的成本以及开发体验的不足让我们对其失去了信心。PowerSync的SQLite实现虽然强大,但在实际使用中出现了严重的性能问题,如查询延迟和初始化时间过长。
问题的根源
经过多次尝试,我们意识到问题的根源在于Web浏览器的限制。所有基于IndexedDB的离线优先解决方案本质上都是“黑客式”的实现,无法在处理大规模数据时保持高性能。无论是关系型数据库还是图数据库,一旦数据量达到一定规模,性能都会急剧下降。
最终解决方案:Replicache
在多次失败后,我们重新审视了Replicache。尽管其闭源和奇怪的定价模式曾让我们望而却步,但它的KV存储设计和卓越的性能最终打动了我们。Replicache在IndexedDB的基础上提供了高效的同步和查询功能,尽管它不支持复杂的搜索和排序,但通过与Orama的结合,我们成功实现了强大的索引和全文搜索功能。
离线优先的未来
离线优先的实现仍然是一个极具挑战性的问题,但随着Triplit、InstantDB等新工具的不断进步,未来有望变得更加简单和高效。我们相信,2025年将是HTTP/REST API逐渐被淘汰的一年,取而代之的是更智能的数据库同步技术。
Marco的探索之旅让我们深刻认识到,离线优先的实现不仅需要强大的技术支撑,还需要对应用场景的深刻理解。尽管过程充满挑战,但我们最终找到了适合Marco的解决方案,并期待未来离线优先技术的进一步发展。
评论总结
评论内容总结:
Replicache+Orama的成功与Triplit的转型
- isaachinman提到Replicache+Orama的成功,并期待尝试Zero。Triplit已转型为开源项目,InstantDB则成熟了许多。
- 引用:"We’ve had great success with Replicache+Orama since this was written."
- 引用:"Triplit has essentially folded as a 'company' and become some sort of open-source initiative instead."
IndexedDB与SQLite的关系
- fmajid指出IndexedDB基于SQLite,认为放弃WebSQL是一个错误。
- 引用:"IndexedDB itself is built on top of... SQLite. Abandoning WebSQL was truly a heinous crime against the Web."
离线优先应用的挑战
- rudedogg强调离线优先应用的限制,特别是SQLite的类型限制和查询规划问题,建议关注RxDB和OPFS。
- 引用:"How are you going to take this loosey-goosey typed data and store it in a backend database when you sync?"
- 引用:"OPFS is a newish thing everyone is using to store SQLite directly instead of wrapping IndexedDB for better performance."
RxDB与LokiJS的使用体验
- cfu28分享使用RxDB和LokiJS的经验,指出客户端数据库缺乏成熟的迁移工具,且IndexedDB查询速度较慢。
- 引用:"I got surprisingly far with RxDB, but it definitely felt like I was pushing these tools and the web platform to their limit."
- 引用:"What surprised me was that a query to indexed db can be slower than a network call."
OPFS的潜力
- dfabulich认为OPFS是解决离线优先应用性能问题的关键,WASM SQLite结合OPFS不再是“hack”。
- 引用:"WASM sqlite on OPFS is, finally, not a hack, and is pretty much exactly what the author needed in the first place."
自定义同步引擎的实现
- hakanshehu分享使用SQLite和OPFS构建离线优先应用的经验,强调Kysely的跨平台查询抽象。
- 引用:"Now we have a full offline-first app in web using SQLite on top of OPFS."
本地优先应用的数据库大小限制
- victorbjorklund提出关于本地优先应用数据库大小的疑问,探讨何时不再适合使用本地优先模式。
- 引用:"What size of db is too big? When does local-first no longer make sense?"
电子邮件工作流的未来
- scarface_74认为电子邮件工作流在2025年将不再重要,Slack等工具已取代内部沟通。
- 引用:"Email though? Except in pre-sales, I can’t imagine anyone using an email heavy workflow in 2025."
直接使用IndexedDB的经验
- nmjenkins分享Fastmail直接使用IndexedDB的经验,认为其性能足够应对多GB的邮箱数据。
- 引用:"The performance has been pretty decent, even with multi-gigabyte mailboxes."
InstantDB的改进
- stopachka介绍InstantDB的最新改进,强调其开发体验的优化。
- 引用:"We’re on a mission to make the best DX possible for building apps."
离线优先与本地优先的对比
- MerrimanInd询问离线优先与本地优先在技术和理念上的重叠。
- 引用:"What’s the overlap between the offline-first and local-first paradigms these days?"
自定义IndexedDB封装
- kaz-inc分享自定义的IndexedDB封装FileDB和FlatDB,用于快速搜索和跨设备同步。
- 引用:"Searching 150k messages in less than 20ms on my 4 year old phone."
Triplit的性能提升
- local_surfer提到Triplit 1.0的性能大幅提升,建议重新考虑其在大规模数据项目中的应用。
- 引用:"Triplit 1.0 had had a massive performance update (up to 10x)."
同步引擎的语义冲突处理
- Existenceblinks批评现有工具未能展示多玩家模式下的同步引擎,特别是语义冲突的处理。
- 引用:"These topic and mentioned tools always fail to demonstrate how sync engine works in multiple players modes."
总结:评论中讨论了多种离线优先和本地优先数据库工具(如Replicache、Orama、Triplit、InstantDB、RxDB等)的优缺点,特别关注了IndexedDB、SQLite和OPFS的性能与适用性。同时,评论者分享了各自的使用经验,并提出了关于数据库大小、同步冲突处理等问题的思考。